OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [m68k/] [ifpsp060/] [src/] [fplsp.S] - Rev 3

Compare with Previous | Blame | View Log

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
M68000 Hi-Performance Microprocessor Division
M68060 Software Package
Production Release P1.00 -- October 10, 1994

M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.

THE SOFTWARE is provided on an "AS IS" basis and without warranty.
To the maximum extent permitted by applicable law,
MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
and any warranty against infringement with regard to the SOFTWARE
(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.

To the maximum extent permitted by applicable law,
IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.

You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
so long as this entire notice is retained without alteration in any modified and/or
redistributed versions, and that such modified versions are clearly identified as such.
No licenses are granted by implication, estoppel or otherwise under any patents
or trademarks of Motorola, Inc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# lfptop.s:
#       This file is appended to the top of the 060ILSP package
# and contains the entry points into the package. The user, in
# effect, branches to one of the branch table entries located here.
#

        bra.l   _facoss_
        short   0x0000
        bra.l   _facosd_
        short   0x0000
        bra.l   _facosx_
        short   0x0000

        bra.l   _fasins_
        short   0x0000
        bra.l   _fasind_
        short   0x0000
        bra.l   _fasinx_
        short   0x0000

        bra.l   _fatans_
        short   0x0000
        bra.l   _fatand_
        short   0x0000
        bra.l   _fatanx_
        short   0x0000

        bra.l   _fatanhs_
        short   0x0000
        bra.l   _fatanhd_
        short   0x0000
        bra.l   _fatanhx_
        short   0x0000

        bra.l   _fcoss_
        short   0x0000
        bra.l   _fcosd_
        short   0x0000
        bra.l   _fcosx_
        short   0x0000

        bra.l   _fcoshs_
        short   0x0000
        bra.l   _fcoshd_
        short   0x0000
        bra.l   _fcoshx_
        short   0x0000

        bra.l   _fetoxs_
        short   0x0000
        bra.l   _fetoxd_
        short   0x0000
        bra.l   _fetoxx_
        short   0x0000

        bra.l   _fetoxm1s_
        short   0x0000
        bra.l   _fetoxm1d_
        short   0x0000
        bra.l   _fetoxm1x_
        short   0x0000

        bra.l   _fgetexps_
        short   0x0000
        bra.l   _fgetexpd_
        short   0x0000
        bra.l   _fgetexpx_
        short   0x0000

        bra.l   _fgetmans_
        short   0x0000
        bra.l   _fgetmand_
        short   0x0000
        bra.l   _fgetmanx_
        short   0x0000

        bra.l   _flog10s_
        short   0x0000
        bra.l   _flog10d_
        short   0x0000
        bra.l   _flog10x_
        short   0x0000

        bra.l   _flog2s_
        short   0x0000
        bra.l   _flog2d_
        short   0x0000
        bra.l   _flog2x_
        short   0x0000

        bra.l   _flogns_
        short   0x0000
        bra.l   _flognd_
        short   0x0000
        bra.l   _flognx_
        short   0x0000

        bra.l   _flognp1s_
        short   0x0000
        bra.l   _flognp1d_
        short   0x0000
        bra.l   _flognp1x_
        short   0x0000

        bra.l   _fmods_
        short   0x0000
        bra.l   _fmodd_
        short   0x0000
        bra.l   _fmodx_
        short   0x0000

        bra.l   _frems_
        short   0x0000
        bra.l   _fremd_
        short   0x0000
        bra.l   _fremx_
        short   0x0000

        bra.l   _fscales_
        short   0x0000
        bra.l   _fscaled_
        short   0x0000
        bra.l   _fscalex_
        short   0x0000

        bra.l   _fsins_
        short   0x0000
        bra.l   _fsind_
        short   0x0000
        bra.l   _fsinx_
        short   0x0000

        bra.l   _fsincoss_
        short   0x0000
        bra.l   _fsincosd_
        short   0x0000
        bra.l   _fsincosx_
        short   0x0000

        bra.l   _fsinhs_
        short   0x0000
        bra.l   _fsinhd_
        short   0x0000
        bra.l   _fsinhx_
        short   0x0000

        bra.l   _ftans_
        short   0x0000
        bra.l   _ftand_
        short   0x0000
        bra.l   _ftanx_
        short   0x0000

        bra.l   _ftanhs_
        short   0x0000
        bra.l   _ftanhd_
        short   0x0000
        bra.l   _ftanhx_
        short   0x0000

        bra.l   _ftentoxs_
        short   0x0000
        bra.l   _ftentoxd_
        short   0x0000
        bra.l   _ftentoxx_
        short   0x0000

        bra.l   _ftwotoxs_
        short   0x0000
        bra.l   _ftwotoxd_
        short   0x0000
        bra.l   _ftwotoxx_
        short   0x0000

        bra.l   _fabss_
        short   0x0000
        bra.l   _fabsd_
        short   0x0000
        bra.l   _fabsx_
        short   0x0000

        bra.l   _fadds_
        short   0x0000
        bra.l   _faddd_
        short   0x0000
        bra.l   _faddx_
        short   0x0000

        bra.l   _fdivs_
        short   0x0000
        bra.l   _fdivd_
        short   0x0000
        bra.l   _fdivx_
        short   0x0000

        bra.l   _fints_
        short   0x0000
        bra.l   _fintd_
        short   0x0000
        bra.l   _fintx_
        short   0x0000

        bra.l   _fintrzs_
        short   0x0000
        bra.l   _fintrzd_
        short   0x0000
        bra.l   _fintrzx_
        short   0x0000

        bra.l   _fmuls_
        short   0x0000
        bra.l   _fmuld_
        short   0x0000
        bra.l   _fmulx_
        short   0x0000

        bra.l   _fnegs_
        short   0x0000
        bra.l   _fnegd_
        short   0x0000
        bra.l   _fnegx_
        short   0x0000

        bra.l   _fsqrts_
        short   0x0000
        bra.l   _fsqrtd_
        short   0x0000
        bra.l   _fsqrtx_
        short   0x0000

        bra.l   _fsubs_
        short   0x0000
        bra.l   _fsubd_
        short   0x0000
        bra.l   _fsubx_
        short   0x0000

# leave room for future possible additions
        align   0x400

#
# This file contains a set of define statements for constants
# in order to promote readability within the corecode itself.
#

set LOCAL_SIZE,         192                     # stack frame size(bytes)
set LV,                 -LOCAL_SIZE             # stack offset

set EXC_SR,             0x4                     # stack status register
set EXC_PC,             0x6                     # stack pc
set EXC_VOFF,           0xa                     # stacked vector offset
set EXC_EA,             0xc                     # stacked <ea>

set EXC_FP,             0x0                     # frame pointer

set EXC_AREGS,          -68                     # offset of all address regs
set EXC_DREGS,          -100                    # offset of all data regs
set EXC_FPREGS,         -36                     # offset of all fp regs

set EXC_A7,             EXC_AREGS+(7*4)         # offset of saved a7
set OLD_A7,             EXC_AREGS+(6*4)         # extra copy of saved a7
set EXC_A6,             EXC_AREGS+(6*4)         # offset of saved a6
set EXC_A5,             EXC_AREGS+(5*4)
set EXC_A4,             EXC_AREGS+(4*4)
set EXC_A3,             EXC_AREGS+(3*4)
set EXC_A2,             EXC_AREGS+(2*4)
set EXC_A1,             EXC_AREGS+(1*4)
set EXC_A0,             EXC_AREGS+(0*4)
set EXC_D7,             EXC_DREGS+(7*4)
set EXC_D6,             EXC_DREGS+(6*4)
set EXC_D5,             EXC_DREGS+(5*4)
set EXC_D4,             EXC_DREGS+(4*4)
set EXC_D3,             EXC_DREGS+(3*4)
set EXC_D2,             EXC_DREGS+(2*4)
set EXC_D1,             EXC_DREGS+(1*4)
set EXC_D0,             EXC_DREGS+(0*4)

set EXC_FP0,            EXC_FPREGS+(0*12)       # offset of saved fp0
set EXC_FP1,            EXC_FPREGS+(1*12)       # offset of saved fp1
set EXC_FP2,            EXC_FPREGS+(2*12)       # offset of saved fp2 (not used)

set FP_SCR1,            LV+80                   # fp scratch 1
set FP_SCR1_EX,         FP_SCR1+0
set FP_SCR1_SGN,        FP_SCR1+2
set FP_SCR1_HI,         FP_SCR1+4
set FP_SCR1_LO,         FP_SCR1+8

set FP_SCR0,            LV+68                   # fp scratch 0
set FP_SCR0_EX,         FP_SCR0+0
set FP_SCR0_SGN,        FP_SCR0+2
set FP_SCR0_HI,         FP_SCR0+4
set FP_SCR0_LO,         FP_SCR0+8

set FP_DST,             LV+56                   # fp destination operand
set FP_DST_EX,          FP_DST+0
set FP_DST_SGN,         FP_DST+2
set FP_DST_HI,          FP_DST+4
set FP_DST_LO,          FP_DST+8

set FP_SRC,             LV+44                   # fp source operand
set FP_SRC_EX,          FP_SRC+0
set FP_SRC_SGN,         FP_SRC+2
set FP_SRC_HI,          FP_SRC+4
set FP_SRC_LO,          FP_SRC+8

set USER_FPIAR,         LV+40                   # FP instr address register

set USER_FPSR,          LV+36                   # FP status register
set FPSR_CC,            USER_FPSR+0             # FPSR condition codes
set FPSR_QBYTE,         USER_FPSR+1             # FPSR qoutient byte
set FPSR_EXCEPT,        USER_FPSR+2             # FPSR exception status byte
set FPSR_AEXCEPT,       USER_FPSR+3             # FPSR accrued exception byte

set USER_FPCR,          LV+32                   # FP control register
set FPCR_ENABLE,        USER_FPCR+2             # FPCR exception enable
set FPCR_MODE,          USER_FPCR+3             # FPCR rounding mode control

set L_SCR3,             LV+28                   # integer scratch 3
set L_SCR2,             LV+24                   # integer scratch 2
set L_SCR1,             LV+20                   # integer scratch 1

set STORE_FLG,          LV+19                   # flag: operand store (ie. not fcmp/ftst)

set EXC_TEMP2,          LV+24                   # temporary space
set EXC_TEMP,           LV+16                   # temporary space

set DTAG,               LV+15                   # destination operand type
set STAG,               LV+14                   # source operand type

set SPCOND_FLG,         LV+10                   # flag: special case (see below)

set EXC_CC,             LV+8                    # saved condition codes
set EXC_EXTWPTR,        LV+4                    # saved current PC (active)
set EXC_EXTWORD,        LV+2                    # saved extension word
set EXC_CMDREG,         LV+2                    # saved extension word
set EXC_OPWORD,         LV+0                    # saved operation word

################################

# Helpful macros

set FTEMP,              0                        # offsets within an
set FTEMP_EX,           0                        # extended precision
set FTEMP_SGN,          2                       # value saved in memory.
set FTEMP_HI,           4
set FTEMP_LO,           8
set FTEMP_GRS,          12

set LOCAL,              0                        # offsets within an
set LOCAL_EX,           0                        # extended precision
set LOCAL_SGN,          2                       # value saved in memory.
set LOCAL_HI,           4
set LOCAL_LO,           8
set LOCAL_GRS,          12

set DST,                0                        # offsets within an
set DST_EX,             0                        # extended precision
set DST_HI,             4                       # value saved in memory.
set DST_LO,             8

set SRC,                0                        # offsets within an
set SRC_EX,             0                        # extended precision
set SRC_HI,             4                       # value saved in memory.
set SRC_LO,             8

set SGL_LO,             0x3f81                  # min sgl prec exponent
set SGL_HI,             0x407e                  # max sgl prec exponent
set DBL_LO,             0x3c01                  # min dbl prec exponent
set DBL_HI,             0x43fe                  # max dbl prec exponent
set EXT_LO,             0x0                     # min ext prec exponent
set EXT_HI,             0x7ffe                  # max ext prec exponent

set EXT_BIAS,           0x3fff                  # extended precision bias
set SGL_BIAS,           0x007f                  # single precision bias
set DBL_BIAS,           0x03ff                  # double precision bias

set NORM,               0x00                    # operand type for STAG/DTAG
set ZERO,               0x01                    # operand type for STAG/DTAG
set INF,                0x02                    # operand type for STAG/DTAG
set QNAN,               0x03                    # operand type for STAG/DTAG
set DENORM,             0x04                    # operand type for STAG/DTAG
set SNAN,               0x05                    # operand type for STAG/DTAG
set UNNORM,             0x06                    # operand type for STAG/DTAG

##################
# FPSR/FPCR bits #
##################
set neg_bit,            0x3                     # negative result
set z_bit,              0x2                     # zero result
set inf_bit,            0x1                     # infinite result
set nan_bit,            0x0                     # NAN result

set q_sn_bit,           0x7                     # sign bit of quotient byte

set bsun_bit,           7                       # branch on unordered
set snan_bit,           6                       # signalling NAN
set operr_bit,          5                       # operand error
set ovfl_bit,           4                       # overflow
set unfl_bit,           3                       # underflow
set dz_bit,             2                       # divide by zero
set inex2_bit,          1                       # inexact result 2
set inex1_bit,          0                        # inexact result 1

set aiop_bit,           7                       # accrued inexact operation bit
set aovfl_bit,          6                       # accrued overflow bit
set aunfl_bit,          5                       # accrued underflow bit
set adz_bit,            4                       # accrued dz bit
set ainex_bit,          3                       # accrued inexact bit

#############################
# FPSR individual bit masks #
#############################
set neg_mask,           0x08000000              # negative bit mask (lw)
set inf_mask,           0x02000000              # infinity bit mask (lw)
set z_mask,             0x04000000              # zero bit mask (lw)
set nan_mask,           0x01000000              # nan bit mask (lw)

set neg_bmask,          0x08                    # negative bit mask (byte)
set inf_bmask,          0x02                    # infinity bit mask (byte)
set z_bmask,            0x04                    # zero bit mask (byte)
set nan_bmask,          0x01                    # nan bit mask (byte)

set bsun_mask,          0x00008000              # bsun exception mask
set snan_mask,          0x00004000              # snan exception mask
set operr_mask,         0x00002000              # operr exception mask
set ovfl_mask,          0x00001000              # overflow exception mask
set unfl_mask,          0x00000800              # underflow exception mask
set dz_mask,            0x00000400              # dz exception mask
set inex2_mask,         0x00000200              # inex2 exception mask
set inex1_mask,         0x00000100              # inex1 exception mask

set aiop_mask,          0x00000080              # accrued illegal operation
set aovfl_mask,         0x00000040              # accrued overflow
set aunfl_mask,         0x00000020              # accrued underflow
set adz_mask,           0x00000010              # accrued divide by zero
set ainex_mask,         0x00000008              # accrued inexact

######################################
# FPSR combinations used in the FPSP #
######################################
set dzinf_mask,         inf_mask+dz_mask+adz_mask
set opnan_mask,         nan_mask+operr_mask+aiop_mask
set nzi_mask,           0x01ffffff              #clears N, Z, and I
set unfinx_mask,        unfl_mask+inex2_mask+aunfl_mask+ainex_mask
set unf2inx_mask,       unfl_mask+inex2_mask+ainex_mask
set ovfinx_mask,        ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
set inx1a_mask,         inex1_mask+ainex_mask
set inx2a_mask,         inex2_mask+ainex_mask
set snaniop_mask,       nan_mask+snan_mask+aiop_mask
set snaniop2_mask,      snan_mask+aiop_mask
set naniop_mask,        nan_mask+aiop_mask
set neginf_mask,        neg_mask+inf_mask
set infaiop_mask,       inf_mask+aiop_mask
set negz_mask,          neg_mask+z_mask
set opaop_mask,         operr_mask+aiop_mask
set unfl_inx_mask,      unfl_mask+aunfl_mask+ainex_mask
set ovfl_inx_mask,      ovfl_mask+aovfl_mask+ainex_mask

#########
# misc. #
#########
set rnd_stky_bit,       29                      # stky bit pos in longword

set sign_bit,           0x7                     # sign bit
set signan_bit,         0x6                     # signalling nan bit

set sgl_thresh,         0x3f81                  # minimum sgl exponent
set dbl_thresh,         0x3c01                  # minimum dbl exponent

set x_mode,             0x0                     # extended precision
set s_mode,             0x4                     # single precision
set d_mode,             0x8                     # double precision

set rn_mode,            0x0                     # round-to-nearest
set rz_mode,            0x1                     # round-to-zero
set rm_mode,            0x2                     # round-tp-minus-infinity
set rp_mode,            0x3                     # round-to-plus-infinity

set mantissalen,        64                      # length of mantissa in bits

set BYTE,               1                       # len(byte) == 1 byte
set WORD,               2                       # len(word) == 2 bytes
set LONG,               4                       # len(longword) == 2 bytes

set BSUN_VEC,           0xc0                    # bsun    vector offset
set INEX_VEC,           0xc4                    # inexact vector offset
set DZ_VEC,             0xc8                    # dz      vector offset
set UNFL_VEC,           0xcc                    # unfl    vector offset
set OPERR_VEC,          0xd0                    # operr   vector offset
set OVFL_VEC,           0xd4                    # ovfl    vector offset
set SNAN_VEC,           0xd8                    # snan    vector offset

###########################
# SPecial CONDition FLaGs #
###########################
set ftrapcc_flg,        0x01                    # flag bit: ftrapcc exception
set fbsun_flg,          0x02                    # flag bit: bsun exception
set mia7_flg,           0x04                    # flag bit: (a7)+ <ea>
set mda7_flg,           0x08                    # flag bit: -(a7) <ea>
set fmovm_flg,          0x40                    # flag bit: fmovm instruction
set immed_flg,          0x80                    # flag bit: &<data> <ea>

set ftrapcc_bit,        0x0
set fbsun_bit,          0x1
set mia7_bit,           0x2
set mda7_bit,           0x3
set immed_bit,          0x7

##################################
# TRANSCENDENTAL "LAST-OP" FLAGS #
##################################
set FMUL_OP,            0x0                     # fmul instr performed last
set FDIV_OP,            0x1                     # fdiv performed last
set FADD_OP,            0x2                     # fadd performed last
set FMOV_OP,            0x3                     # fmov performed last

#############
# CONSTANTS #
#############
T1:     long            0x40C62D38,0xD3D64634   # 16381 LOG2 LEAD
T2:     long            0x3D6F90AE,0xB1E75CC7   # 16381 LOG2 TRAIL

PI:     long            0x40000000,0xC90FDAA2,0x2168C235,0x00000000
PIBY2:  long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000

TWOBYPI:
        long            0x3FE45F30,0x6DC9C883

#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fsins_
_fsins_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L0_2s
        bsr.l           ssin                    # operand is a NORM
        bra.b           _L0_6s
_L0_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L0_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L0_6s
_L0_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L0_4s                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L0_6s
_L0_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L0_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L0_6s
_L0_5s:
        bsr.l           ssind                   # operand is a DENORM
_L0_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fsind_
_fsind_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L0_2d
        bsr.l           ssin                    # operand is a NORM
        bra.b           _L0_6d
_L0_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L0_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L0_6d
_L0_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L0_4d                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L0_6d
_L0_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L0_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L0_6d
_L0_5d:
        bsr.l           ssind                   # operand is a DENORM
_L0_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fsinx_
_fsinx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L0_2x
        bsr.l           ssin                    # operand is a NORM
        bra.b           _L0_6x
_L0_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L0_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L0_6x
_L0_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L0_4x                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L0_6x
_L0_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L0_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L0_6x
_L0_5x:
        bsr.l           ssind                   # operand is a DENORM
_L0_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fcoss_
_fcoss_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L1_2s
        bsr.l           scos                    # operand is a NORM
        bra.b           _L1_6s
_L1_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L1_3s                  # no
        bsr.l           ld_pone                 # yes
        bra.b           _L1_6s
_L1_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L1_4s                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L1_6s
_L1_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L1_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L1_6s
_L1_5s:
        bsr.l           scosd                   # operand is a DENORM
_L1_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fcosd_
_fcosd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L1_2d
        bsr.l           scos                    # operand is a NORM
        bra.b           _L1_6d
_L1_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L1_3d                  # no
        bsr.l           ld_pone                 # yes
        bra.b           _L1_6d
_L1_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L1_4d                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L1_6d
_L1_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L1_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L1_6d
_L1_5d:
        bsr.l           scosd                   # operand is a DENORM
_L1_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fcosx_
_fcosx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L1_2x
        bsr.l           scos                    # operand is a NORM
        bra.b           _L1_6x
_L1_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L1_3x                  # no
        bsr.l           ld_pone                 # yes
        bra.b           _L1_6x
_L1_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L1_4x                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L1_6x
_L1_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L1_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L1_6x
_L1_5x:
        bsr.l           scosd                   # operand is a DENORM
_L1_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fsinhs_
_fsinhs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L2_2s
        bsr.l           ssinh                   # operand is a NORM
        bra.b           _L2_6s
_L2_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L2_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L2_6s
_L2_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L2_4s                  # no
        bsr.l           src_inf                 # yes
        bra.b           _L2_6s
_L2_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L2_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L2_6s
_L2_5s:
        bsr.l           ssinhd                  # operand is a DENORM
_L2_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fsinhd_
_fsinhd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L2_2d
        bsr.l           ssinh                   # operand is a NORM
        bra.b           _L2_6d
_L2_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L2_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L2_6d
_L2_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L2_4d                  # no
        bsr.l           src_inf                 # yes
        bra.b           _L2_6d
_L2_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L2_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L2_6d
_L2_5d:
        bsr.l           ssinhd                  # operand is a DENORM
_L2_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fsinhx_
_fsinhx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L2_2x
        bsr.l           ssinh                   # operand is a NORM
        bra.b           _L2_6x
_L2_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L2_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L2_6x
_L2_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L2_4x                  # no
        bsr.l           src_inf                 # yes
        bra.b           _L2_6x
_L2_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L2_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L2_6x
_L2_5x:
        bsr.l           ssinhd                  # operand is a DENORM
_L2_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _flognp1s_
_flognp1s_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L3_2s
        bsr.l           slognp1                 # operand is a NORM
        bra.b           _L3_6s
_L3_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L3_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L3_6s
_L3_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L3_4s                  # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L3_6s
_L3_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L3_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L3_6s
_L3_5s:
        bsr.l           slognp1d                        # operand is a DENORM
_L3_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flognp1d_
_flognp1d_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L3_2d
        bsr.l           slognp1                 # operand is a NORM
        bra.b           _L3_6d
_L3_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L3_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L3_6d
_L3_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L3_4d                  # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L3_6d
_L3_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L3_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L3_6d
_L3_5d:
        bsr.l           slognp1d                        # operand is a DENORM
_L3_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flognp1x_
_flognp1x_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L3_2x
        bsr.l           slognp1                 # operand is a NORM
        bra.b           _L3_6x
_L3_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L3_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L3_6x
_L3_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L3_4x                  # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L3_6x
_L3_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L3_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L3_6x
_L3_5x:
        bsr.l           slognp1d                        # operand is a DENORM
_L3_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fetoxm1s_
_fetoxm1s_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L4_2s
        bsr.l           setoxm1                 # operand is a NORM
        bra.b           _L4_6s
_L4_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L4_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L4_6s
_L4_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L4_4s                  # no
        bsr.l           setoxm1i                        # yes
        bra.b           _L4_6s
_L4_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L4_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L4_6s
_L4_5s:
        bsr.l           setoxm1d                        # operand is a DENORM
_L4_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fetoxm1d_
_fetoxm1d_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L4_2d
        bsr.l           setoxm1                 # operand is a NORM
        bra.b           _L4_6d
_L4_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L4_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L4_6d
_L4_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L4_4d                  # no
        bsr.l           setoxm1i                        # yes
        bra.b           _L4_6d
_L4_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L4_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L4_6d
_L4_5d:
        bsr.l           setoxm1d                        # operand is a DENORM
_L4_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fetoxm1x_
_fetoxm1x_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L4_2x
        bsr.l           setoxm1                 # operand is a NORM
        bra.b           _L4_6x
_L4_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L4_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L4_6x
_L4_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L4_4x                  # no
        bsr.l           setoxm1i                        # yes
        bra.b           _L4_6x
_L4_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L4_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L4_6x
_L4_5x:
        bsr.l           setoxm1d                        # operand is a DENORM
_L4_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _ftanhs_
_ftanhs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L5_2s
        bsr.l           stanh                   # operand is a NORM
        bra.b           _L5_6s
_L5_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L5_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L5_6s
_L5_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L5_4s                  # no
        bsr.l           src_one                 # yes
        bra.b           _L5_6s
_L5_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L5_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L5_6s
_L5_5s:
        bsr.l           stanhd                  # operand is a DENORM
_L5_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftanhd_
_ftanhd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L5_2d
        bsr.l           stanh                   # operand is a NORM
        bra.b           _L5_6d
_L5_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L5_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L5_6d
_L5_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L5_4d                  # no
        bsr.l           src_one                 # yes
        bra.b           _L5_6d
_L5_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L5_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L5_6d
_L5_5d:
        bsr.l           stanhd                  # operand is a DENORM
_L5_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftanhx_
_ftanhx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L5_2x
        bsr.l           stanh                   # operand is a NORM
        bra.b           _L5_6x
_L5_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L5_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L5_6x
_L5_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L5_4x                  # no
        bsr.l           src_one                 # yes
        bra.b           _L5_6x
_L5_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L5_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L5_6x
_L5_5x:
        bsr.l           stanhd                  # operand is a DENORM
_L5_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fatans_
_fatans_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L6_2s
        bsr.l           satan                   # operand is a NORM
        bra.b           _L6_6s
_L6_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L6_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L6_6s
_L6_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L6_4s                  # no
        bsr.l           spi_2                   # yes
        bra.b           _L6_6s
_L6_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L6_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L6_6s
_L6_5s:
        bsr.l           satand                  # operand is a DENORM
_L6_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fatand_
_fatand_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L6_2d
        bsr.l           satan                   # operand is a NORM
        bra.b           _L6_6d
_L6_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L6_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L6_6d
_L6_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L6_4d                  # no
        bsr.l           spi_2                   # yes
        bra.b           _L6_6d
_L6_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L6_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L6_6d
_L6_5d:
        bsr.l           satand                  # operand is a DENORM
_L6_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fatanx_
_fatanx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L6_2x
        bsr.l           satan                   # operand is a NORM
        bra.b           _L6_6x
_L6_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L6_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L6_6x
_L6_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L6_4x                  # no
        bsr.l           spi_2                   # yes
        bra.b           _L6_6x
_L6_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L6_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L6_6x
_L6_5x:
        bsr.l           satand                  # operand is a DENORM
_L6_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fasins_
_fasins_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L7_2s
        bsr.l           sasin                   # operand is a NORM
        bra.b           _L7_6s
_L7_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L7_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L7_6s
_L7_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L7_4s                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L7_6s
_L7_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L7_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L7_6s
_L7_5s:
        bsr.l           sasind                  # operand is a DENORM
_L7_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fasind_
_fasind_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L7_2d
        bsr.l           sasin                   # operand is a NORM
        bra.b           _L7_6d
_L7_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L7_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L7_6d
_L7_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L7_4d                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L7_6d
_L7_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L7_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L7_6d
_L7_5d:
        bsr.l           sasind                  # operand is a DENORM
_L7_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fasinx_
_fasinx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L7_2x
        bsr.l           sasin                   # operand is a NORM
        bra.b           _L7_6x
_L7_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L7_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L7_6x
_L7_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L7_4x                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L7_6x
_L7_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L7_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L7_6x
_L7_5x:
        bsr.l           sasind                  # operand is a DENORM
_L7_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fatanhs_
_fatanhs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L8_2s
        bsr.l           satanh                  # operand is a NORM
        bra.b           _L8_6s
_L8_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L8_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L8_6s
_L8_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L8_4s                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L8_6s
_L8_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L8_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L8_6s
_L8_5s:
        bsr.l           satanhd                 # operand is a DENORM
_L8_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fatanhd_
_fatanhd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L8_2d
        bsr.l           satanh                  # operand is a NORM
        bra.b           _L8_6d
_L8_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L8_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L8_6d
_L8_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L8_4d                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L8_6d
_L8_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L8_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L8_6d
_L8_5d:
        bsr.l           satanhd                 # operand is a DENORM
_L8_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fatanhx_
_fatanhx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L8_2x
        bsr.l           satanh                  # operand is a NORM
        bra.b           _L8_6x
_L8_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L8_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L8_6x
_L8_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L8_4x                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L8_6x
_L8_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L8_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L8_6x
_L8_5x:
        bsr.l           satanhd                 # operand is a DENORM
_L8_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _ftans_
_ftans_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L9_2s
        bsr.l           stan                    # operand is a NORM
        bra.b           _L9_6s
_L9_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L9_3s                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L9_6s
_L9_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L9_4s                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L9_6s
_L9_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L9_5s                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L9_6s
_L9_5s:
        bsr.l           stand                   # operand is a DENORM
_L9_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftand_
_ftand_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L9_2d
        bsr.l           stan                    # operand is a NORM
        bra.b           _L9_6d
_L9_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L9_3d                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L9_6d
_L9_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L9_4d                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L9_6d
_L9_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L9_5d                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L9_6d
_L9_5d:
        bsr.l           stand                   # operand is a DENORM
_L9_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftanx_
_ftanx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L9_2x
        bsr.l           stan                    # operand is a NORM
        bra.b           _L9_6x
_L9_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L9_3x                  # no
        bsr.l           src_zero                        # yes
        bra.b           _L9_6x
_L9_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L9_4x                  # no
        bsr.l           t_operr                 # yes
        bra.b           _L9_6x
_L9_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L9_5x                  # no
        bsr.l           src_qnan                        # yes
        bra.b           _L9_6x
_L9_5x:
        bsr.l           stand                   # operand is a DENORM
_L9_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fetoxs_
_fetoxs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L10_2s
        bsr.l           setox                   # operand is a NORM
        bra.b           _L10_6s
_L10_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L10_3s                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L10_6s
_L10_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L10_4s                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L10_6s
_L10_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L10_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L10_6s
_L10_5s:
        bsr.l           setoxd                  # operand is a DENORM
_L10_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fetoxd_
_fetoxd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L10_2d
        bsr.l           setox                   # operand is a NORM
        bra.b           _L10_6d
_L10_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L10_3d                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L10_6d
_L10_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L10_4d                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L10_6d
_L10_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L10_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L10_6d
_L10_5d:
        bsr.l           setoxd                  # operand is a DENORM
_L10_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fetoxx_
_fetoxx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L10_2x
        bsr.l           setox                   # operand is a NORM
        bra.b           _L10_6x
_L10_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L10_3x                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L10_6x
_L10_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L10_4x                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L10_6x
_L10_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L10_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L10_6x
_L10_5x:
        bsr.l           setoxd                  # operand is a DENORM
_L10_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _ftwotoxs_
_ftwotoxs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L11_2s
        bsr.l           stwotox                 # operand is a NORM
        bra.b           _L11_6s
_L11_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L11_3s                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L11_6s
_L11_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L11_4s                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L11_6s
_L11_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L11_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L11_6s
_L11_5s:
        bsr.l           stwotoxd                        # operand is a DENORM
_L11_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftwotoxd_
_ftwotoxd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L11_2d
        bsr.l           stwotox                 # operand is a NORM
        bra.b           _L11_6d
_L11_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L11_3d                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L11_6d
_L11_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L11_4d                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L11_6d
_L11_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L11_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L11_6d
_L11_5d:
        bsr.l           stwotoxd                        # operand is a DENORM
_L11_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftwotoxx_
_ftwotoxx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L11_2x
        bsr.l           stwotox                 # operand is a NORM
        bra.b           _L11_6x
_L11_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L11_3x                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L11_6x
_L11_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L11_4x                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L11_6x
_L11_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L11_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L11_6x
_L11_5x:
        bsr.l           stwotoxd                        # operand is a DENORM
_L11_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _ftentoxs_
_ftentoxs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L12_2s
        bsr.l           stentox                 # operand is a NORM
        bra.b           _L12_6s
_L12_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L12_3s                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L12_6s
_L12_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L12_4s                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L12_6s
_L12_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L12_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L12_6s
_L12_5s:
        bsr.l           stentoxd                        # operand is a DENORM
_L12_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftentoxd_
_ftentoxd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L12_2d
        bsr.l           stentox                 # operand is a NORM
        bra.b           _L12_6d
_L12_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L12_3d                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L12_6d
_L12_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L12_4d                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L12_6d
_L12_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L12_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L12_6d
_L12_5d:
        bsr.l           stentoxd                        # operand is a DENORM
_L12_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _ftentoxx_
_ftentoxx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L12_2x
        bsr.l           stentox                 # operand is a NORM
        bra.b           _L12_6x
_L12_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L12_3x                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L12_6x
_L12_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L12_4x                 # no
        bsr.l           szr_inf                 # yes
        bra.b           _L12_6x
_L12_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L12_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L12_6x
_L12_5x:
        bsr.l           stentoxd                        # operand is a DENORM
_L12_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _flogns_
_flogns_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L13_2s
        bsr.l           slogn                   # operand is a NORM
        bra.b           _L13_6s
_L13_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L13_3s                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L13_6s
_L13_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L13_4s                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L13_6s
_L13_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L13_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L13_6s
_L13_5s:
        bsr.l           slognd                  # operand is a DENORM
_L13_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flognd_
_flognd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L13_2d
        bsr.l           slogn                   # operand is a NORM
        bra.b           _L13_6d
_L13_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L13_3d                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L13_6d
_L13_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L13_4d                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L13_6d
_L13_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L13_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L13_6d
_L13_5d:
        bsr.l           slognd                  # operand is a DENORM
_L13_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flognx_
_flognx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L13_2x
        bsr.l           slogn                   # operand is a NORM
        bra.b           _L13_6x
_L13_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L13_3x                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L13_6x
_L13_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L13_4x                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L13_6x
_L13_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L13_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L13_6x
_L13_5x:
        bsr.l           slognd                  # operand is a DENORM
_L13_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _flog10s_
_flog10s_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L14_2s
        bsr.l           slog10                  # operand is a NORM
        bra.b           _L14_6s
_L14_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L14_3s                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L14_6s
_L14_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L14_4s                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L14_6s
_L14_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L14_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L14_6s
_L14_5s:
        bsr.l           slog10d                 # operand is a DENORM
_L14_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flog10d_
_flog10d_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L14_2d
        bsr.l           slog10                  # operand is a NORM
        bra.b           _L14_6d
_L14_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L14_3d                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L14_6d
_L14_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L14_4d                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L14_6d
_L14_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L14_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L14_6d
_L14_5d:
        bsr.l           slog10d                 # operand is a DENORM
_L14_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flog10x_
_flog10x_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L14_2x
        bsr.l           slog10                  # operand is a NORM
        bra.b           _L14_6x
_L14_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L14_3x                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L14_6x
_L14_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L14_4x                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L14_6x
_L14_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L14_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L14_6x
_L14_5x:
        bsr.l           slog10d                 # operand is a DENORM
_L14_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _flog2s_
_flog2s_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L15_2s
        bsr.l           slog2                   # operand is a NORM
        bra.b           _L15_6s
_L15_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L15_3s                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L15_6s
_L15_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L15_4s                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L15_6s
_L15_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L15_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L15_6s
_L15_5s:
        bsr.l           slog2d                  # operand is a DENORM
_L15_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flog2d_
_flog2d_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L15_2d
        bsr.l           slog2                   # operand is a NORM
        bra.b           _L15_6d
_L15_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L15_3d                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L15_6d
_L15_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L15_4d                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L15_6d
_L15_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L15_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L15_6d
_L15_5d:
        bsr.l           slog2d                  # operand is a DENORM
_L15_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _flog2x_
_flog2x_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L15_2x
        bsr.l           slog2                   # operand is a NORM
        bra.b           _L15_6x
_L15_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L15_3x                 # no
        bsr.l           t_dz2                   # yes
        bra.b           _L15_6x
_L15_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L15_4x                 # no
        bsr.l           sopr_inf                        # yes
        bra.b           _L15_6x
_L15_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L15_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L15_6x
_L15_5x:
        bsr.l           slog2d                  # operand is a DENORM
_L15_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fcoshs_
_fcoshs_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L16_2s
        bsr.l           scosh                   # operand is a NORM
        bra.b           _L16_6s
_L16_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L16_3s                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L16_6s
_L16_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L16_4s                 # no
        bsr.l           ld_pinf                 # yes
        bra.b           _L16_6s
_L16_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L16_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L16_6s
_L16_5s:
        bsr.l           scoshd                  # operand is a DENORM
_L16_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fcoshd_
_fcoshd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L16_2d
        bsr.l           scosh                   # operand is a NORM
        bra.b           _L16_6d
_L16_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L16_3d                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L16_6d
_L16_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L16_4d                 # no
        bsr.l           ld_pinf                 # yes
        bra.b           _L16_6d
_L16_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L16_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L16_6d
_L16_5d:
        bsr.l           scoshd                  # operand is a DENORM
_L16_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fcoshx_
_fcoshx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L16_2x
        bsr.l           scosh                   # operand is a NORM
        bra.b           _L16_6x
_L16_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L16_3x                 # no
        bsr.l           ld_pone                 # yes
        bra.b           _L16_6x
_L16_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L16_4x                 # no
        bsr.l           ld_pinf                 # yes
        bra.b           _L16_6x
_L16_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L16_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L16_6x
_L16_5x:
        bsr.l           scoshd                  # operand is a DENORM
_L16_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _facoss_
_facoss_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L17_2s
        bsr.l           sacos                   # operand is a NORM
        bra.b           _L17_6s
_L17_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L17_3s                 # no
        bsr.l           ld_ppi2                 # yes
        bra.b           _L17_6s
_L17_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L17_4s                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L17_6s
_L17_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L17_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L17_6s
_L17_5s:
        bsr.l           sacosd                  # operand is a DENORM
_L17_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _facosd_
_facosd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L17_2d
        bsr.l           sacos                   # operand is a NORM
        bra.b           _L17_6d
_L17_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L17_3d                 # no
        bsr.l           ld_ppi2                 # yes
        bra.b           _L17_6d
_L17_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L17_4d                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L17_6d
_L17_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L17_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L17_6d
_L17_5d:
        bsr.l           sacosd                  # operand is a DENORM
_L17_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _facosx_
_facosx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L17_2x
        bsr.l           sacos                   # operand is a NORM
        bra.b           _L17_6x
_L17_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L17_3x                 # no
        bsr.l           ld_ppi2                 # yes
        bra.b           _L17_6x
_L17_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L17_4x                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L17_6x
_L17_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L17_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L17_6x
_L17_5x:
        bsr.l           sacosd                  # operand is a DENORM
_L17_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fgetexps_
_fgetexps_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L18_2s
        bsr.l           sgetexp                 # operand is a NORM
        bra.b           _L18_6s
_L18_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L18_3s                 # no
        bsr.l           src_zero                        # yes
        bra.b           _L18_6s
_L18_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L18_4s                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L18_6s
_L18_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L18_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L18_6s
_L18_5s:
        bsr.l           sgetexpd                        # operand is a DENORM
_L18_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fgetexpd_
_fgetexpd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L18_2d
        bsr.l           sgetexp                 # operand is a NORM
        bra.b           _L18_6d
_L18_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L18_3d                 # no
        bsr.l           src_zero                        # yes
        bra.b           _L18_6d
_L18_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L18_4d                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L18_6d
_L18_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L18_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L18_6d
_L18_5d:
        bsr.l           sgetexpd                        # operand is a DENORM
_L18_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fgetexpx_
_fgetexpx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L18_2x
        bsr.l           sgetexp                 # operand is a NORM
        bra.b           _L18_6x
_L18_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L18_3x                 # no
        bsr.l           src_zero                        # yes
        bra.b           _L18_6x
_L18_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L18_4x                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L18_6x
_L18_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L18_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L18_6x
_L18_5x:
        bsr.l           sgetexpd                        # operand is a DENORM
_L18_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fgetmans_
_fgetmans_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L19_2s
        bsr.l           sgetman                 # operand is a NORM
        bra.b           _L19_6s
_L19_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L19_3s                 # no
        bsr.l           src_zero                        # yes
        bra.b           _L19_6s
_L19_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L19_4s                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L19_6s
_L19_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L19_5s                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L19_6s
_L19_5s:
        bsr.l           sgetmand                        # operand is a DENORM
_L19_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fgetmand_
_fgetmand_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L19_2d
        bsr.l           sgetman                 # operand is a NORM
        bra.b           _L19_6d
_L19_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L19_3d                 # no
        bsr.l           src_zero                        # yes
        bra.b           _L19_6d
_L19_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L19_4d                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L19_6d
_L19_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L19_5d                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L19_6d
_L19_5d:
        bsr.l           sgetmand                        # operand is a DENORM
_L19_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fgetmanx_
_fgetmanx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L19_2x
        bsr.l           sgetman                 # operand is a NORM
        bra.b           _L19_6x
_L19_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L19_3x                 # no
        bsr.l           src_zero                        # yes
        bra.b           _L19_6x
_L19_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L19_4x                 # no
        bsr.l           t_operr                 # yes
        bra.b           _L19_6x
_L19_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L19_5x                 # no
        bsr.l           src_qnan                        # yes
        bra.b           _L19_6x
_L19_5x:
        bsr.l           sgetmand                        # operand is a DENORM
_L19_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# MONADIC TEMPLATE                                                      #
#########################################################################
        global          _fsincoss_
_fsincoss_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L20_2s
        bsr.l           ssincos                 # operand is a NORM
        bra.b           _L20_6s
_L20_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L20_3s                 # no
        bsr.l           ssincosz                        # yes
        bra.b           _L20_6s
_L20_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L20_4s                 # no
        bsr.l           ssincosi                        # yes
        bra.b           _L20_6s
_L20_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L20_5s                 # no
        bsr.l           ssincosqnan                     # yes
        bra.b           _L20_6s
_L20_5s:
        bsr.l           ssincosd                        # operand is a DENORM
_L20_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         &0x03,-(%sp)            # store off fp0/fp1
        fmovm.x         (%sp)+,&0x40            # fp0 now in fp1
        fmovm.x         (%sp)+,&0x80            # fp1 now in fp0
        unlk            %a6
        rts

        global          _fsincosd_
_fsincosd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl input
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        mov.b           %d1,STAG(%a6)
        tst.b           %d1
        bne.b           _L20_2d
        bsr.l           ssincos                 # operand is a NORM
        bra.b           _L20_6d
_L20_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L20_3d                 # no
        bsr.l           ssincosz                        # yes
        bra.b           _L20_6d
_L20_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L20_4d                 # no
        bsr.l           ssincosi                        # yes
        bra.b           _L20_6d
_L20_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L20_5d                 # no
        bsr.l           ssincosqnan                     # yes
        bra.b           _L20_6d
_L20_5d:
        bsr.l           ssincosd                        # operand is a DENORM
_L20_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         &0x03,-(%sp)            # store off fp0/fp1
        fmovm.x         (%sp)+,&0x40            # fp0 now in fp1
        fmovm.x         (%sp)+,&0x80            # fp1 now in fp0
        unlk            %a6
        rts

        global          _fsincosx_
_fsincosx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_SRC(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext input
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.b           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        tst.b           %d1
        bne.b           _L20_2x
        bsr.l           ssincos                 # operand is a NORM
        bra.b           _L20_6x
_L20_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L20_3x                 # no
        bsr.l           ssincosz                        # yes
        bra.b           _L20_6x
_L20_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L20_4x                 # no
        bsr.l           ssincosi                        # yes
        bra.b           _L20_6x
_L20_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L20_5x                 # no
        bsr.l           ssincosqnan                     # yes
        bra.b           _L20_6x
_L20_5x:
        bsr.l           ssincosd                        # operand is a DENORM
_L20_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         &0x03,-(%sp)            # store off fp0/fp1
        fmovm.x         (%sp)+,&0x40            # fp0 now in fp1
        fmovm.x         (%sp)+,&0x80            # fp1 now in fp0
        unlk            %a6
        rts


#########################################################################
# DYADIC TEMPLATE                                                       #
#########################################################################
        global          _frems_
_frems_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl dst
        fmov.x          %fp0,FP_DST(%a6)
        lea             FP_DST(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        fmov.s          0xc(%a6),%fp0           # load sgl src
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L21_2s
        bsr.l           srem_snorm                      # operand is a NORM
        bra.b           _L21_6s
_L21_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L21_3s                 # no
        bsr.l           srem_szero                      # yes
        bra.b           _L21_6s
_L21_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L21_4s                 # no
        bsr.l           srem_sinf                       # yes
        bra.b           _L21_6s
_L21_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L21_5s                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L21_6s
_L21_5s:
        bsr.l           srem_sdnrm                      # operand is a DENORM
_L21_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fremd_
_fremd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl dst
        fmov.x          %fp0,FP_DST(%a6)
        lea             FP_DST(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        fmov.d          0x10(%a6),%fp0          # load dbl src
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L21_2d
        bsr.l           srem_snorm                      # operand is a NORM
        bra.b           _L21_6d
_L21_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L21_3d                 # no
        bsr.l           srem_szero                      # yes
        bra.b           _L21_6d
_L21_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L21_4d                 # no
        bsr.l           srem_sinf                       # yes
        bra.b           _L21_6d
_L21_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L21_5d                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L21_6d
_L21_5d:
        bsr.l           srem_sdnrm                      # operand is a DENORM
_L21_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fremx_
_fremx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_DST(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext dst
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        lea             FP_SRC(%a6),%a0
        mov.l           0x14+0x0(%a6),0x0(%a0)  # load ext src
        mov.l           0x14+0x4(%a6),0x4(%a0)
        mov.l           0x14+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L21_2x
        bsr.l           srem_snorm                      # operand is a NORM
        bra.b           _L21_6x
_L21_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L21_3x                 # no
        bsr.l           srem_szero                      # yes
        bra.b           _L21_6x
_L21_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L21_4x                 # no
        bsr.l           srem_sinf                       # yes
        bra.b           _L21_6x
_L21_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L21_5x                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L21_6x
_L21_5x:
        bsr.l           srem_sdnrm                      # operand is a DENORM
_L21_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# DYADIC TEMPLATE                                                       #
#########################################################################
        global          _fmods_
_fmods_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl dst
        fmov.x          %fp0,FP_DST(%a6)
        lea             FP_DST(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        fmov.s          0xc(%a6),%fp0           # load sgl src
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L22_2s
        bsr.l           smod_snorm                      # operand is a NORM
        bra.b           _L22_6s
_L22_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L22_3s                 # no
        bsr.l           smod_szero                      # yes
        bra.b           _L22_6s
_L22_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L22_4s                 # no
        bsr.l           smod_sinf                       # yes
        bra.b           _L22_6s
_L22_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L22_5s                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L22_6s
_L22_5s:
        bsr.l           smod_sdnrm                      # operand is a DENORM
_L22_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fmodd_
_fmodd_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl dst
        fmov.x          %fp0,FP_DST(%a6)
        lea             FP_DST(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        fmov.d          0x10(%a6),%fp0          # load dbl src
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L22_2d
        bsr.l           smod_snorm                      # operand is a NORM
        bra.b           _L22_6d
_L22_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L22_3d                 # no
        bsr.l           smod_szero                      # yes
        bra.b           _L22_6d
_L22_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L22_4d                 # no
        bsr.l           smod_sinf                       # yes
        bra.b           _L22_6d
_L22_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L22_5d                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L22_6d
_L22_5d:
        bsr.l           smod_sdnrm                      # operand is a DENORM
_L22_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fmodx_
_fmodx_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_DST(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext dst
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        lea             FP_SRC(%a6),%a0
        mov.l           0x14+0x0(%a6),0x0(%a0)  # load ext src
        mov.l           0x14+0x4(%a6),0x4(%a0)
        mov.l           0x14+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L22_2x
        bsr.l           smod_snorm                      # operand is a NORM
        bra.b           _L22_6x
_L22_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L22_3x                 # no
        bsr.l           smod_szero                      # yes
        bra.b           _L22_6x
_L22_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L22_4x                 # no
        bsr.l           smod_sinf                       # yes
        bra.b           _L22_6x
_L22_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L22_5x                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L22_6x
_L22_5x:
        bsr.l           smod_sdnrm                      # operand is a DENORM
_L22_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# DYADIC TEMPLATE                                                       #
#########################################################################
        global          _fscales_
_fscales_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.s          0x8(%a6),%fp0           # load sgl dst
        fmov.x          %fp0,FP_DST(%a6)
        lea             FP_DST(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        fmov.s          0xc(%a6),%fp0           # load sgl src
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L23_2s
        bsr.l           sscale_snorm                    # operand is a NORM
        bra.b           _L23_6s
_L23_2s:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L23_3s                 # no
        bsr.l           sscale_szero                    # yes
        bra.b           _L23_6s
_L23_3s:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L23_4s                 # no
        bsr.l           sscale_sinf                     # yes
        bra.b           _L23_6s
_L23_4s:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L23_5s                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L23_6s
_L23_5s:
        bsr.l           sscale_sdnrm                    # operand is a DENORM
_L23_6s:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fscaled_
_fscaled_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        fmov.d          0x8(%a6),%fp0           # load dbl dst
        fmov.x          %fp0,FP_DST(%a6)
        lea             FP_DST(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        fmov.d          0x10(%a6),%fp0          # load dbl src
        fmov.x          %fp0,FP_SRC(%a6)
        lea             FP_SRC(%a6),%a0
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L23_2d
        bsr.l           sscale_snorm                    # operand is a NORM
        bra.b           _L23_6d
_L23_2d:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L23_3d                 # no
        bsr.l           sscale_szero                    # yes
        bra.b           _L23_6d
_L23_3d:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L23_4d                 # no
        bsr.l           sscale_sinf                     # yes
        bra.b           _L23_6d
_L23_4d:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L23_5d                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L23_6d
_L23_5d:
        bsr.l           sscale_sdnrm                    # operand is a DENORM
_L23_6d:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts

        global          _fscalex_
_fscalex_:
        link            %a6,&-LOCAL_SIZE

        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
        fmovm.l         %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs
        fmovm.x         &0xc0,EXC_FP0(%a6)      # save fp0/fp1

        fmov.l          &0x0,%fpcr              # zero FPCR

#
#       copy, convert, and tag input argument
#
        lea             FP_DST(%a6),%a0
        mov.l           0x8+0x0(%a6),0x0(%a0)   # load ext dst
        mov.l           0x8+0x4(%a6),0x4(%a0)
        mov.l           0x8+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,DTAG(%a6)

        lea             FP_SRC(%a6),%a0
        mov.l           0x14+0x0(%a6),0x0(%a0)  # load ext src
        mov.l           0x14+0x4(%a6),0x4(%a0)
        mov.l           0x14+0x8(%a6),0x8(%a0)
        bsr.l           tag                     # fetch operand type
        mov.b           %d0,STAG(%a6)
        mov.l           %d0,%d1

        andi.l          &0x00ff00ff,USER_FPSR(%a6)

        clr.l           %d0
        mov.b           FPCR_MODE(%a6),%d0      # pass rnd mode,prec

        lea             FP_SRC(%a6),%a0         # pass ptr to src
        lea             FP_DST(%a6),%a1         # pass ptr to dst

        tst.b           %d1
        bne.b           _L23_2x
        bsr.l           sscale_snorm                    # operand is a NORM
        bra.b           _L23_6x
_L23_2x:
        cmpi.b          %d1,&ZERO               # is operand a ZERO?
        bne.b           _L23_3x                 # no
        bsr.l           sscale_szero                    # yes
        bra.b           _L23_6x
_L23_3x:
        cmpi.b          %d1,&INF                # is operand an INF?
        bne.b           _L23_4x                 # no
        bsr.l           sscale_sinf                     # yes
        bra.b           _L23_6x
_L23_4x:
        cmpi.b          %d1,&QNAN               # is operand a QNAN?
        bne.b           _L23_5x                 # no
        bsr.l           sop_sqnan                       # yes
        bra.b           _L23_6x
_L23_5x:
        bsr.l           sscale_sdnrm                    # operand is a DENORM
_L23_6x:

#
#       Result is now in FP0
#
        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs
        fmovm.x         EXC_FP1(%a6),&0x40      # restore fp1
        unlk            %a6
        rts


#########################################################################
# ssin():     computes the sine of a normalized input                   #
# ssind():    computes the sine of a denormalized input                 #
# scos():     computes the cosine of a normalized input                 #
# scosd():    computes the cosine of a denormalized input               #
# ssincos():  computes the sine and cosine of a normalized input        #
# ssincosd(): computes the sine and cosine of a denormalized input      #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = sin(X) or cos(X)                                          #
#                                                                       #
#    For ssincos(X):                                                    #
#       fp0 = sin(X)                                                    #
#       fp1 = cos(X)                                                    #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 1 ulp in 64 significant bit, i.e. #
#       within 0.5001 ulp to 53 bits if the result is subsequently      #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       SIN and COS:                                                    #
#       1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1.  #
#                                                                       #
#       2. If |X| >= 15Pi or |X| < 2**(-40), go to 7.                   #
#                                                                       #
#       3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
#               k = N mod 4, so in particular, k = 0,1,2,or 3.          #
#               Overwrite k by k := k + AdjN.                           #
#                                                                       #
#       4. If k is even, go to 6.                                       #
#                                                                       #
#       5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j.                 #
#               Return sgn*cos(r) where cos(r) is approximated by an    #
#               even polynomial in r, 1 + r*r*(B1+s*(B2+ ... + s*B8)),  #
#               s = r*r.                                                #
#               Exit.                                                   #
#                                                                       #
#       6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r)  #
#               where sin(r) is approximated by an odd polynomial in r  #
#               r + r*s*(A1+s*(A2+ ... + s*A7)),        s = r*r.        #
#               Exit.                                                   #
#                                                                       #
#       7. If |X| > 1, go to 9.                                         #
#                                                                       #
#       8. (|X|<2**(-40)) If SIN is invoked, return X;                  #
#               otherwise return 1.                                     #
#                                                                       #
#       9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi,           #
#               go back to 3.                                           #
#                                                                       #
#       SINCOS:                                                         #
#       1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.                   #
#                                                                       #
#       2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
#               k = N mod 4, so in particular, k = 0,1,2,or 3.          #
#                                                                       #
#       3. If k is even, go to 5.                                       #
#                                                                       #
#       4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), ie.  #
#               j1 exclusive or with the l.s.b. of k.                   #
#               sgn1 := (-1)**j1, sgn2 := (-1)**j2.                     #
#               SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where   #
#               sin(r) and cos(r) are computed as odd and even          #
#               polynomials in r, respectively. Exit                    #
#                                                                       #
#       5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1.                 #
#               SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where   #
#               sin(r) and cos(r) are computed as odd and even          #
#               polynomials in r, respectively. Exit                    #
#                                                                       #
#       6. If |X| > 1, go to 8.                                         #
#                                                                       #
#       7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit.              #
#                                                                       #
#       8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi,           #
#               go back to 2.                                           #
#                                                                       #
#########################################################################

SINA7:  long            0xBD6AAA77,0xCCC994F5
SINA6:  long            0x3DE61209,0x7AAE8DA1
SINA5:  long            0xBE5AE645,0x2A118AE4
SINA4:  long            0x3EC71DE3,0xA5341531
SINA3:  long            0xBF2A01A0,0x1A018B59,0x00000000,0x00000000
SINA2:  long            0x3FF80000,0x88888888,0x888859AF,0x00000000
SINA1:  long            0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000

COSB8:  long            0x3D2AC4D0,0xD6011EE3
COSB7:  long            0xBDA9396F,0x9F45AC19
COSB6:  long            0x3E21EED9,0x0612C972
COSB5:  long            0xBE927E4F,0xB79D9FCF
COSB4:  long            0x3EFA01A0,0x1A01D423,0x00000000,0x00000000
COSB3:  long            0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000
COSB2:  long            0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E
COSB1:  long            0xBF000000

        set             INARG,FP_SCR0

        set             X,FP_SCR0
#       set             XDCARE,X+2
        set             XFRAC,X+4

        set             RPRIME,FP_SCR0
        set             SPRIME,FP_SCR1

        set             POSNEG1,L_SCR1
        set             TWOTO63,L_SCR1

        set             ENDFLAG,L_SCR2
        set             INT,L_SCR2

        set             ADJN,L_SCR3

############################################
        global          ssin
ssin:
        mov.l           &0,ADJN(%a6)            # yes; SET ADJN TO 0
        bra.b           SINBGN

############################################
        global          scos
scos:
        mov.l           &1,ADJN(%a6)            # yes; SET ADJN TO 1

############################################
SINBGN:
#--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE

        fmov.x          (%a0),%fp0              # LOAD INPUT
        fmov.x          %fp0,X(%a6)             # save input at X

# "COMPACTIFY" X
        mov.l           (%a0),%d1               # put exp in hi word
        mov.w           4(%a0),%d1              # fetch hi(man)
        and.l           &0x7FFFFFFF,%d1         # strip sign

        cmpi.l          %d1,&0x3FD78000         # is |X| >= 2**(-40)?
        bge.b           SOK1                    # no
        bra.w           SINSM                   # yes; input is very small

SOK1:
        cmp.l           %d1,&0x4004BC7E         # is |X| < 15 PI?
        blt.b           SINMAIN                 # no
        bra.w           SREDUCEX                # yes; input is very large

#--THIS IS THE USUAL CASE, |X| <= 15 PI.
#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
SINMAIN:
        fmov.x          %fp0,%fp1
        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI

        lea             PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32

        fmov.l          %fp1,INT(%a6)           # CONVERT TO INTEGER

        mov.l           INT(%a6),%d1            # make a copy of N
        asl.l           &4,%d1                  # N *= 16
        add.l           %d1,%a1                 # tbl_addr = a1 + (N*16)

# A1 IS THE ADDRESS OF N*PIBY2
# ...WHICH IS IN TWO PIECES Y1 & Y2
        fsub.x          (%a1)+,%fp0             # X-Y1
        fsub.s          (%a1),%fp0              # fp0 = R = (X-Y1)-Y2

SINCONT:
#--continuation from REDUCEX

#--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED
        mov.l           INT(%a6),%d1
        add.l           ADJN(%a6),%d1           # SEE IF D0 IS ODD OR EVEN
        ror.l           &1,%d1                  # D0 WAS ODD IFF D0 IS NEGATIVE
        cmp.l           %d1,&0
        blt.w           COSPOLY

#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
#--THEN WE RETURN       SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY
#--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE
#--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS
#--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))])
#--WHERE T=S*S.
#--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION
#--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT.
SINPOLY:
        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3

        fmov.x          %fp0,X(%a6)             # X IS R
        fmul.x          %fp0,%fp0               # FP0 IS S

        fmov.d          SINA7(%pc),%fp3
        fmov.d          SINA6(%pc),%fp2

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # FP1 IS T

        ror.l           &1,%d1
        and.l           &0x80000000,%d1
# ...LEAST SIG. BIT OF D0 IN SIGN POSITION
        eor.l           %d1,X(%a6)              # X IS NOW R'= SGN*R

        fmul.x          %fp1,%fp3               # TA7
        fmul.x          %fp1,%fp2               # TA6

        fadd.d          SINA5(%pc),%fp3         # A5+TA7
        fadd.d          SINA4(%pc),%fp2         # A4+TA6

        fmul.x          %fp1,%fp3               # T(A5+TA7)
        fmul.x          %fp1,%fp2               # T(A4+TA6)

        fadd.d          SINA3(%pc),%fp3         # A3+T(A5+TA7)
        fadd.x          SINA2(%pc),%fp2         # A2+T(A4+TA6)

        fmul.x          %fp3,%fp1               # T(A3+T(A5+TA7))

        fmul.x          %fp0,%fp2               # S(A2+T(A4+TA6))
        fadd.x          SINA1(%pc),%fp1         # A1+T(A3+T(A5+TA7))
        fmul.x          X(%a6),%fp0             # R'*S

        fadd.x          %fp2,%fp1               # [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))]

        fmul.x          %fp1,%fp0               # SIN(R')-R'

        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3

        fmov.l          %d0,%fpcr               # restore users round mode,prec
        fadd.x          X(%a6),%fp0             # last inst - possible exception set
        bra             t_inx2

#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
#--THEN WE RETURN       SGN*COS(R). SGN*COS(R) IS COMPUTED BY
#--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE
#--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS
#--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))])
#--WHERE T=S*S.
#--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION
#--WHILE B2 AND B3 ARE IN DOUBLE-EXTENDED FORMAT, B1 IS -1/2
#--AND IS THEREFORE STORED AS SINGLE PRECISION.
COSPOLY:
        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3

        fmul.x          %fp0,%fp0               # FP0 IS S

        fmov.d          COSB8(%pc),%fp2
        fmov.d          COSB7(%pc),%fp3

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # FP1 IS T

        fmov.x          %fp0,X(%a6)             # X IS S
        ror.l           &1,%d1
        and.l           &0x80000000,%d1
# ...LEAST SIG. BIT OF D0 IN SIGN POSITION

        fmul.x          %fp1,%fp2               # TB8

        eor.l           %d1,X(%a6)              # X IS NOW S'= SGN*S
        and.l           &0x80000000,%d1

        fmul.x          %fp1,%fp3               # TB7

        or.l            &0x3F800000,%d1         # D0 IS SGN IN SINGLE
        mov.l           %d1,POSNEG1(%a6)

        fadd.d          COSB6(%pc),%fp2         # B6+TB8
        fadd.d          COSB5(%pc),%fp3         # B5+TB7

        fmul.x          %fp1,%fp2               # T(B6+TB8)
        fmul.x          %fp1,%fp3               # T(B5+TB7)

        fadd.d          COSB4(%pc),%fp2         # B4+T(B6+TB8)
        fadd.x          COSB3(%pc),%fp3         # B3+T(B5+TB7)

        fmul.x          %fp1,%fp2               # T(B4+T(B6+TB8))
        fmul.x          %fp3,%fp1               # T(B3+T(B5+TB7))

        fadd.x          COSB2(%pc),%fp2         # B2+T(B4+T(B6+TB8))
        fadd.s          COSB1(%pc),%fp1         # B1+T(B3+T(B5+TB7))

        fmul.x          %fp2,%fp0               # S(B2+T(B4+T(B6+TB8)))

        fadd.x          %fp1,%fp0

        fmul.x          X(%a6),%fp0

        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3

        fmov.l          %d0,%fpcr               # restore users round mode,prec
        fadd.s          POSNEG1(%a6),%fp0       # last inst - possible exception set
        bra             t_inx2

##############################################

# SINe: Big OR Small?
#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION.
#--IF |X| < 2**(-40), RETURN X OR 1.
SINBORS:
        cmp.l           %d1,&0x3FFF8000
        bgt.l           SREDUCEX

SINSM:
        mov.l           ADJN(%a6),%d1
        cmp.l           %d1,&0
        bgt.b           COSTINY

# here, the operation may underflow iff the precision is sgl or dbl.
# extended denorms are handled through another entry point.
SINTINY:
#       mov.w           &0x0000,XDCARE(%a6)     # JUST IN CASE

        fmov.l          %d0,%fpcr               # restore users round mode,prec
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          X(%a6),%fp0             # last inst - possible exception set
        bra             t_catch

COSTINY:
        fmov.s          &0x3F800000,%fp0        # fp0 = 1.0
        fmov.l          %d0,%fpcr               # restore users round mode,prec
        fadd.s          &0x80800000,%fp0        # last inst - possible exception set
        bra             t_pinx2

################################################
        global          ssind
#--SIN(X) = X FOR DENORMALIZED X
ssind:
        bra             t_extdnrm

############################################
        global          scosd
#--COS(X) = 1 FOR DENORMALIZED X
scosd:
        fmov.s          &0x3F800000,%fp0        # fp0 = 1.0
        bra             t_pinx2

##################################################

        global          ssincos
ssincos:
#--SET ADJN TO 4
        mov.l           &4,ADJN(%a6)

        fmov.x          (%a0),%fp0              # LOAD INPUT
        fmov.x          %fp0,X(%a6)

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1         # COMPACTIFY X

        cmp.l           %d1,&0x3FD78000         # |X| >= 2**(-40)?
        bge.b           SCOK1
        bra.w           SCSM

SCOK1:
        cmp.l           %d1,&0x4004BC7E         # |X| < 15 PI?
        blt.b           SCMAIN
        bra.w           SREDUCEX


#--THIS IS THE USUAL CASE, |X| <= 15 PI.
#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
SCMAIN:
        fmov.x          %fp0,%fp1

        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI

        lea             PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32

        fmov.l          %fp1,INT(%a6)           # CONVERT TO INTEGER

        mov.l           INT(%a6),%d1
        asl.l           &4,%d1
        add.l           %d1,%a1                 # ADDRESS OF N*PIBY2, IN Y1, Y2

        fsub.x          (%a1)+,%fp0             # X-Y1
        fsub.s          (%a1),%fp0              # FP0 IS R = (X-Y1)-Y2

SCCONT:
#--continuation point from REDUCEX

        mov.l           INT(%a6),%d1
        ror.l           &1,%d1
        cmp.l           %d1,&0                   # D0 < 0 IFF N IS ODD
        bge.w           NEVEN

SNODD:
#--REGISTERS SAVED SO FAR: D0, A0, FP2.
        fmovm.x         &0x04,-(%sp)            # save fp2

        fmov.x          %fp0,RPRIME(%a6)
        fmul.x          %fp0,%fp0               # FP0 IS S = R*R
        fmov.d          SINA7(%pc),%fp1         # A7
        fmov.d          COSB8(%pc),%fp2         # B8
        fmul.x          %fp0,%fp1               # SA7
        fmul.x          %fp0,%fp2               # SB8

        mov.l           %d2,-(%sp)
        mov.l           %d1,%d2
        ror.l           &1,%d2
        and.l           &0x80000000,%d2
        eor.l           %d1,%d2
        and.l           &0x80000000,%d2

        fadd.d          SINA6(%pc),%fp1         # A6+SA7
        fadd.d          COSB7(%pc),%fp2         # B7+SB8

        fmul.x          %fp0,%fp1               # S(A6+SA7)
        eor.l           %d2,RPRIME(%a6)
        mov.l           (%sp)+,%d2
        fmul.x          %fp0,%fp2               # S(B7+SB8)
        ror.l           &1,%d1
        and.l           &0x80000000,%d1
        mov.l           &0x3F800000,POSNEG1(%a6)
        eor.l           %d1,POSNEG1(%a6)

        fadd.d          SINA5(%pc),%fp1         # A5+S(A6+SA7)
        fadd.d          COSB6(%pc),%fp2         # B6+S(B7+SB8)

        fmul.x          %fp0,%fp1               # S(A5+S(A6+SA7))
        fmul.x          %fp0,%fp2               # S(B6+S(B7+SB8))
        fmov.x          %fp0,SPRIME(%a6)

        fadd.d          SINA4(%pc),%fp1         # A4+S(A5+S(A6+SA7))
        eor.l           %d1,SPRIME(%a6)
        fadd.d          COSB5(%pc),%fp2         # B5+S(B6+S(B7+SB8))

        fmul.x          %fp0,%fp1               # S(A4+...)
        fmul.x          %fp0,%fp2               # S(B5+...)

        fadd.d          SINA3(%pc),%fp1         # A3+S(A4+...)
        fadd.d          COSB4(%pc),%fp2         # B4+S(B5+...)

        fmul.x          %fp0,%fp1               # S(A3+...)
        fmul.x          %fp0,%fp2               # S(B4+...)

        fadd.x          SINA2(%pc),%fp1         # A2+S(A3+...)
        fadd.x          COSB3(%pc),%fp2         # B3+S(B4+...)

        fmul.x          %fp0,%fp1               # S(A2+...)
        fmul.x          %fp0,%fp2               # S(B3+...)

        fadd.x          SINA1(%pc),%fp1         # A1+S(A2+...)
        fadd.x          COSB2(%pc),%fp2         # B2+S(B3+...)

        fmul.x          %fp0,%fp1               # S(A1+...)
        fmul.x          %fp2,%fp0               # S(B2+...)

        fmul.x          RPRIME(%a6),%fp1        # R'S(A1+...)
        fadd.s          COSB1(%pc),%fp0         # B1+S(B2...)
        fmul.x          SPRIME(%a6),%fp0        # S'(B1+S(B2+...))

        fmovm.x         (%sp)+,&0x20            # restore fp2

        fmov.l          %d0,%fpcr
        fadd.x          RPRIME(%a6),%fp1        # COS(X)
        bsr             sto_cos                 # store cosine result
        fadd.s          POSNEG1(%a6),%fp0       # SIN(X)
        bra             t_inx2

NEVEN:
#--REGISTERS SAVED SO FAR: FP2.
        fmovm.x         &0x04,-(%sp)            # save fp2

        fmov.x          %fp0,RPRIME(%a6)
        fmul.x          %fp0,%fp0               # FP0 IS S = R*R

        fmov.d          COSB8(%pc),%fp1         # B8
        fmov.d          SINA7(%pc),%fp2         # A7

        fmul.x          %fp0,%fp1               # SB8
        fmov.x          %fp0,SPRIME(%a6)
        fmul.x          %fp0,%fp2               # SA7

        ror.l           &1,%d1
        and.l           &0x80000000,%d1

        fadd.d          COSB7(%pc),%fp1         # B7+SB8
        fadd.d          SINA6(%pc),%fp2         # A6+SA7

        eor.l           %d1,RPRIME(%a6)
        eor.l           %d1,SPRIME(%a6)

        fmul.x          %fp0,%fp1               # S(B7+SB8)

        or.l            &0x3F800000,%d1
        mov.l           %d1,POSNEG1(%a6)

        fmul.x          %fp0,%fp2               # S(A6+SA7)

        fadd.d          COSB6(%pc),%fp1         # B6+S(B7+SB8)
        fadd.d          SINA5(%pc),%fp2         # A5+S(A6+SA7)

        fmul.x          %fp0,%fp1               # S(B6+S(B7+SB8))
        fmul.x          %fp0,%fp2               # S(A5+S(A6+SA7))

        fadd.d          COSB5(%pc),%fp1         # B5+S(B6+S(B7+SB8))
        fadd.d          SINA4(%pc),%fp2         # A4+S(A5+S(A6+SA7))

        fmul.x          %fp0,%fp1               # S(B5+...)
        fmul.x          %fp0,%fp2               # S(A4+...)

        fadd.d          COSB4(%pc),%fp1         # B4+S(B5+...)
        fadd.d          SINA3(%pc),%fp2         # A3+S(A4+...)

        fmul.x          %fp0,%fp1               # S(B4+...)
        fmul.x          %fp0,%fp2               # S(A3+...)

        fadd.x          COSB3(%pc),%fp1         # B3+S(B4+...)
        fadd.x          SINA2(%pc),%fp2         # A2+S(A3+...)

        fmul.x          %fp0,%fp1               # S(B3+...)
        fmul.x          %fp0,%fp2               # S(A2+...)

        fadd.x          COSB2(%pc),%fp1         # B2+S(B3+...)
        fadd.x          SINA1(%pc),%fp2         # A1+S(A2+...)

        fmul.x          %fp0,%fp1               # S(B2+...)
        fmul.x          %fp2,%fp0               # s(a1+...)


        fadd.s          COSB1(%pc),%fp1         # B1+S(B2...)
        fmul.x          RPRIME(%a6),%fp0        # R'S(A1+...)
        fmul.x          SPRIME(%a6),%fp1        # S'(B1+S(B2+...))

        fmovm.x         (%sp)+,&0x20            # restore fp2

        fmov.l          %d0,%fpcr
        fadd.s          POSNEG1(%a6),%fp1       # COS(X)
        bsr             sto_cos                 # store cosine result
        fadd.x          RPRIME(%a6),%fp0        # SIN(X)
        bra             t_inx2

################################################

SCBORS:
        cmp.l           %d1,&0x3FFF8000
        bgt.w           SREDUCEX

################################################

SCSM:
#       mov.w           &0x0000,XDCARE(%a6)
        fmov.s          &0x3F800000,%fp1

        fmov.l          %d0,%fpcr
        fsub.s          &0x00800000,%fp1
        bsr             sto_cos                 # store cosine result
        fmov.l          %fpcr,%d0               # d0 must have fpcr,too
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          X(%a6),%fp0
        bra             t_catch

##############################################

        global          ssincosd
#--SIN AND COS OF X FOR DENORMALIZED X
ssincosd:
        mov.l           %d0,-(%sp)              # save d0
        fmov.s          &0x3F800000,%fp1
        bsr             sto_cos                 # store cosine result
        mov.l           (%sp)+,%d0              # restore d0
        bra             t_extdnrm

############################################

#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW.
#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING
#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE.
SREDUCEX:
        fmovm.x         &0x3c,-(%sp)            # save {fp2-fp5}
        mov.l           %d2,-(%sp)              # save d2
        fmov.s          &0x00000000,%fp1        # fp1 = 0

#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that
#--there is a danger of unwanted overflow in first LOOP iteration.  In this
#--case, reduce argument by one remainder step to make subsequent reduction
#--safe.
        cmp.l           %d1,&0x7ffeffff         # is arg dangerously large?
        bne.b           SLOOP                   # no

# yes; create 2**16383*PI/2
        mov.w           &0x7ffe,FP_SCR0_EX(%a6)
        mov.l           &0xc90fdaa2,FP_SCR0_HI(%a6)
        clr.l           FP_SCR0_LO(%a6)

# create low half of 2**16383*PI/2 at FP_SCR1
        mov.w           &0x7fdc,FP_SCR1_EX(%a6)
        mov.l           &0x85a308d3,FP_SCR1_HI(%a6)
        clr.l           FP_SCR1_LO(%a6)

        ftest.x         %fp0                    # test sign of argument
        fblt.w          sred_neg

        or.b            &0x80,FP_SCR0_EX(%a6)   # positive arg
        or.b            &0x80,FP_SCR1_EX(%a6)
sred_neg:
        fadd.x          FP_SCR0(%a6),%fp0       # high part of reduction is exact
        fmov.x          %fp0,%fp1               # save high result in fp1
        fadd.x          FP_SCR1(%a6),%fp0       # low part of reduction
        fsub.x          %fp0,%fp1               # determine low component of result
        fadd.x          FP_SCR1(%a6),%fp1       # fp0/fp1 are reduced argument.

#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
#--integer quotient will be stored in N
#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
SLOOP:
        fmov.x          %fp0,INARG(%a6)         # +-2**K * F, 1 <= F < 2
        mov.w           INARG(%a6),%d1
        mov.l           %d1,%a1                 # save a copy of D0
        and.l           &0x00007FFF,%d1
        sub.l           &0x00003FFF,%d1         # d0 = K
        cmp.l           %d1,&28
        ble.b           SLASTLOOP
SCONTLOOP:
        sub.l           &27,%d1                 # d0 = L := K-27
        mov.b           &0,ENDFLAG(%a6)
        bra.b           SWORK
SLASTLOOP:
        clr.l           %d1                     # d0 = L := 0
        mov.b           &1,ENDFLAG(%a6)

SWORK:
#--FIND THE REMAINDER OF (R,r) W.R.T.   2**L * (PI/2). L IS SO CHOSEN
#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29.

#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63),
#--2**L * (PIby2_1), 2**L * (PIby2_2)

        mov.l           &0x00003FFE,%d2         # BIASED EXP OF 2/PI
        sub.l           %d1,%d2                 # BIASED EXP OF 2**(-L)*(2/PI)

        mov.l           &0xA2F9836E,FP_SCR0_HI(%a6)
        mov.l           &0x4E44152A,FP_SCR0_LO(%a6)
        mov.w           %d2,FP_SCR0_EX(%a6)     # FP_SCR0 = 2**(-L)*(2/PI)

        fmov.x          %fp0,%fp2
        fmul.x          FP_SCR0(%a6),%fp2       # fp2 = X * 2**(-L)*(2/PI)

#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN
#--FLOATING POINT FORMAT, THE TWO FMOVE'S       FMOVE.L FP <--> N
#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT
#--(SIGN(INARG)*2**63   +       FP2) - SIGN(INARG)*2**63 WILL GIVE
#--US THE DESIRED VALUE IN FLOATING POINT.
        mov.l           %a1,%d2
        swap            %d2
        and.l           &0x80000000,%d2
        or.l            &0x5F000000,%d2         # d2 = SIGN(INARG)*2**63 IN SGL
        mov.l           %d2,TWOTO63(%a6)
        fadd.s          TWOTO63(%a6),%fp2       # THE FRACTIONAL PART OF FP1 IS ROUNDED
        fsub.s          TWOTO63(%a6),%fp2       # fp2 = N
#       fint.x          %fp2

#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2
        mov.l           %d1,%d2                 # d2 = L

        add.l           &0x00003FFF,%d2         # BIASED EXP OF 2**L * (PI/2)
        mov.w           %d2,FP_SCR0_EX(%a6)
        mov.l           &0xC90FDAA2,FP_SCR0_HI(%a6)
        clr.l           FP_SCR0_LO(%a6)         # FP_SCR0 = 2**(L) * Piby2_1

        add.l           &0x00003FDD,%d1
        mov.w           %d1,FP_SCR1_EX(%a6)
        mov.l           &0x85A308D3,FP_SCR1_HI(%a6)
        clr.l           FP_SCR1_LO(%a6)         # FP_SCR1 = 2**(L) * Piby2_2

        mov.b           ENDFLAG(%a6),%d1

#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and
#--P2 = 2**(L) * Piby2_2
        fmov.x          %fp2,%fp4               # fp4 = N
        fmul.x          FP_SCR0(%a6),%fp4       # fp4 = W = N*P1
        fmov.x          %fp2,%fp5               # fp5 = N
        fmul.x          FP_SCR1(%a6),%fp5       # fp5 = w = N*P2
        fmov.x          %fp4,%fp3               # fp3 = W = N*P1

#--we want P+p = W+w  but  |p| <= half ulp of P
#--Then, we need to compute  A := R-P   and  a := r-p
        fadd.x          %fp5,%fp3               # fp3 = P
        fsub.x          %fp3,%fp4               # fp4 = W-P

        fsub.x          %fp3,%fp0               # fp0 = A := R - P
        fadd.x          %fp5,%fp4               # fp4 = p = (W-P)+w

        fmov.x          %fp0,%fp3               # fp3 = A
        fsub.x          %fp4,%fp1               # fp1 = a := r - p

#--Now we need to normalize (A,a) to  "new (R,r)" where R+r = A+a but
#--|r| <= half ulp of R.
        fadd.x          %fp1,%fp0               # fp0 = R := A+a
#--No need to calculate r if this is the last loop
        cmp.b           %d1,&0
        bgt.w           SRESTORE

#--Need to calculate r
        fsub.x          %fp0,%fp3               # fp3 = A-R
        fadd.x          %fp3,%fp1               # fp1 = r := (A-R)+a
        bra.w           SLOOP

SRESTORE:
        fmov.l          %fp2,INT(%a6)
        mov.l           (%sp)+,%d2              # restore d2
        fmovm.x         (%sp)+,&0x3c            # restore {fp2-fp5}

        mov.l           ADJN(%a6),%d1
        cmp.l           %d1,&4

        blt.w           SINCONT
        bra.w           SCCONT

#########################################################################
# stan():  computes the tangent of a normalized input                   #
# stand(): computes the tangent of a denormalized input                 #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = tan(X)                                                    #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulp in 64 significant bit, i.e. #
#       within 0.5001 ulp to 53 bits if the result is subsequently      #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.                   #
#                                                                       #
#       2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
#               k = N mod 2, so in particular, k = 0 or 1.              #
#                                                                       #
#       3. If k is odd, go to 5.                                        #
#                                                                       #
#       4. (k is even) Tan(X) = tan(r) and tan(r) is approximated by a  #
#               rational function U/V where                             #
#               U = r + r*s*(P1 + s*(P2 + s*P3)), and                   #
#               V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))),  s = r*r.      #
#               Exit.                                                   #
#                                                                       #
#       4. (k is odd) Tan(X) = -cot(r). Since tan(r) is approximated by #
#               a rational function U/V where                           #
#               U = r + r*s*(P1 + s*(P2 + s*P3)), and                   #
#               V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r,       #
#               -Cot(r) = -V/U. Exit.                                   #
#                                                                       #
#       6. If |X| > 1, go to 8.                                         #
#                                                                       #
#       7. (|X|<2**(-40)) Tan(X) = X. Exit.                             #
#                                                                       #
#       8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back   #
#               to 2.                                                   #
#                                                                       #
#########################################################################

TANQ4:
        long            0x3EA0B759,0xF50F8688
TANP3:
        long            0xBEF2BAA5,0xA8924F04

TANQ3:
        long            0xBF346F59,0xB39BA65F,0x00000000,0x00000000

TANP2:
        long            0x3FF60000,0xE073D3FC,0x199C4A00,0x00000000

TANQ2:
        long            0x3FF90000,0xD23CD684,0x15D95FA1,0x00000000

TANP1:
        long            0xBFFC0000,0x8895A6C5,0xFB423BCA,0x00000000

TANQ1:
        long            0xBFFD0000,0xEEF57E0D,0xA84BC8CE,0x00000000

INVTWOPI:
        long            0x3FFC0000,0xA2F9836E,0x4E44152A,0x00000000

TWOPI1:
        long            0x40010000,0xC90FDAA2,0x00000000,0x00000000
TWOPI2:
        long            0x3FDF0000,0x85A308D4,0x00000000,0x00000000

#--N*PI/2, -32 <= N <= 32, IN A LEADING TERM IN EXT. AND TRAILING
#--TERM IN SGL. NOTE THAT PI IS 64-BIT LONG, THUS N*PI/2 IS AT
#--MOST 69 BITS LONG.
#       global          PITBL
PITBL:
        long            0xC0040000,0xC90FDAA2,0x2168C235,0x21800000
        long            0xC0040000,0xC2C75BCD,0x105D7C23,0xA0D00000
        long            0xC0040000,0xBC7EDCF7,0xFF523611,0xA1E80000
        long            0xC0040000,0xB6365E22,0xEE46F000,0x21480000
        long            0xC0040000,0xAFEDDF4D,0xDD3BA9EE,0xA1200000
        long            0xC0040000,0xA9A56078,0xCC3063DD,0x21FC0000
        long            0xC0040000,0xA35CE1A3,0xBB251DCB,0x21100000
        long            0xC0040000,0x9D1462CE,0xAA19D7B9,0xA1580000
        long            0xC0040000,0x96CBE3F9,0x990E91A8,0x21E00000
        long            0xC0040000,0x90836524,0x88034B96,0x20B00000
        long            0xC0040000,0x8A3AE64F,0x76F80584,0xA1880000
        long            0xC0040000,0x83F2677A,0x65ECBF73,0x21C40000
        long            0xC0030000,0xFB53D14A,0xA9C2F2C2,0x20000000
        long            0xC0030000,0xEEC2D3A0,0x87AC669F,0x21380000
        long            0xC0030000,0xE231D5F6,0x6595DA7B,0xA1300000
        long            0xC0030000,0xD5A0D84C,0x437F4E58,0x9FC00000
        long            0xC0030000,0xC90FDAA2,0x2168C235,0x21000000
        long            0xC0030000,0xBC7EDCF7,0xFF523611,0xA1680000
        long            0xC0030000,0xAFEDDF4D,0xDD3BA9EE,0xA0A00000
        long            0xC0030000,0xA35CE1A3,0xBB251DCB,0x20900000
        long            0xC0030000,0x96CBE3F9,0x990E91A8,0x21600000
        long            0xC0030000,0x8A3AE64F,0x76F80584,0xA1080000
        long            0xC0020000,0xFB53D14A,0xA9C2F2C2,0x1F800000
        long            0xC0020000,0xE231D5F6,0x6595DA7B,0xA0B00000
        long            0xC0020000,0xC90FDAA2,0x2168C235,0x20800000
        long            0xC0020000,0xAFEDDF4D,0xDD3BA9EE,0xA0200000
        long            0xC0020000,0x96CBE3F9,0x990E91A8,0x20E00000
        long            0xC0010000,0xFB53D14A,0xA9C2F2C2,0x1F000000
        long            0xC0010000,0xC90FDAA2,0x2168C235,0x20000000
        long            0xC0010000,0x96CBE3F9,0x990E91A8,0x20600000
        long            0xC0000000,0xC90FDAA2,0x2168C235,0x1F800000
        long            0xBFFF0000,0xC90FDAA2,0x2168C235,0x1F000000
        long            0x00000000,0x00000000,0x00000000,0x00000000
        long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x9F000000
        long            0x40000000,0xC90FDAA2,0x2168C235,0x9F800000
        long            0x40010000,0x96CBE3F9,0x990E91A8,0xA0600000
        long            0x40010000,0xC90FDAA2,0x2168C235,0xA0000000
        long            0x40010000,0xFB53D14A,0xA9C2F2C2,0x9F000000
        long            0x40020000,0x96CBE3F9,0x990E91A8,0xA0E00000
        long            0x40020000,0xAFEDDF4D,0xDD3BA9EE,0x20200000
        long            0x40020000,0xC90FDAA2,0x2168C235,0xA0800000
        long            0x40020000,0xE231D5F6,0x6595DA7B,0x20B00000
        long            0x40020000,0xFB53D14A,0xA9C2F2C2,0x9F800000
        long            0x40030000,0x8A3AE64F,0x76F80584,0x21080000
        long            0x40030000,0x96CBE3F9,0x990E91A8,0xA1600000
        long            0x40030000,0xA35CE1A3,0xBB251DCB,0xA0900000
        long            0x40030000,0xAFEDDF4D,0xDD3BA9EE,0x20A00000
        long            0x40030000,0xBC7EDCF7,0xFF523611,0x21680000
        long            0x40030000,0xC90FDAA2,0x2168C235,0xA1000000
        long            0x40030000,0xD5A0D84C,0x437F4E58,0x1FC00000
        long            0x40030000,0xE231D5F6,0x6595DA7B,0x21300000
        long            0x40030000,0xEEC2D3A0,0x87AC669F,0xA1380000
        long            0x40030000,0xFB53D14A,0xA9C2F2C2,0xA0000000
        long            0x40040000,0x83F2677A,0x65ECBF73,0xA1C40000
        long            0x40040000,0x8A3AE64F,0x76F80584,0x21880000
        long            0x40040000,0x90836524,0x88034B96,0xA0B00000
        long            0x40040000,0x96CBE3F9,0x990E91A8,0xA1E00000
        long            0x40040000,0x9D1462CE,0xAA19D7B9,0x21580000
        long            0x40040000,0xA35CE1A3,0xBB251DCB,0xA1100000
        long            0x40040000,0xA9A56078,0xCC3063DD,0xA1FC0000
        long            0x40040000,0xAFEDDF4D,0xDD3BA9EE,0x21200000
        long            0x40040000,0xB6365E22,0xEE46F000,0xA1480000
        long            0x40040000,0xBC7EDCF7,0xFF523611,0x21E80000
        long            0x40040000,0xC2C75BCD,0x105D7C23,0x20D00000
        long            0x40040000,0xC90FDAA2,0x2168C235,0xA1800000

        set             INARG,FP_SCR0

        set             TWOTO63,L_SCR1
        set             INT,L_SCR1
        set             ENDFLAG,L_SCR2

        global          stan
stan:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1

        cmp.l           %d1,&0x3FD78000         # |X| >= 2**(-40)?
        bge.b           TANOK1
        bra.w           TANSM
TANOK1:
        cmp.l           %d1,&0x4004BC7E         # |X| < 15 PI?
        blt.b           TANMAIN
        bra.w           REDUCEX

TANMAIN:
#--THIS IS THE USUAL CASE, |X| <= 15 PI.
#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
        fmov.x          %fp0,%fp1
        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI

        lea.l           PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32

        fmov.l          %fp1,%d1                # CONVERT TO INTEGER

        asl.l           &4,%d1
        add.l           %d1,%a1                 # ADDRESS N*PIBY2 IN Y1, Y2

        fsub.x          (%a1)+,%fp0             # X-Y1

        fsub.s          (%a1),%fp0              # FP0 IS R = (X-Y1)-Y2

        ror.l           &5,%d1
        and.l           &0x80000000,%d1         # D0 WAS ODD IFF D0 < 0

TANCONT:
        fmovm.x         &0x0c,-(%sp)            # save fp2,fp3

        cmp.l           %d1,&0
        blt.w           NODD

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # S = R*R

        fmov.d          TANQ4(%pc),%fp3
        fmov.d          TANP3(%pc),%fp2

        fmul.x          %fp1,%fp3               # SQ4
        fmul.x          %fp1,%fp2               # SP3

        fadd.d          TANQ3(%pc),%fp3         # Q3+SQ4
        fadd.x          TANP2(%pc),%fp2         # P2+SP3

        fmul.x          %fp1,%fp3               # S(Q3+SQ4)
        fmul.x          %fp1,%fp2               # S(P2+SP3)

        fadd.x          TANQ2(%pc),%fp3         # Q2+S(Q3+SQ4)
        fadd.x          TANP1(%pc),%fp2         # P1+S(P2+SP3)

        fmul.x          %fp1,%fp3               # S(Q2+S(Q3+SQ4))
        fmul.x          %fp1,%fp2               # S(P1+S(P2+SP3))

        fadd.x          TANQ1(%pc),%fp3         # Q1+S(Q2+S(Q3+SQ4))
        fmul.x          %fp0,%fp2               # RS(P1+S(P2+SP3))

        fmul.x          %fp3,%fp1               # S(Q1+S(Q2+S(Q3+SQ4)))

        fadd.x          %fp2,%fp0               # R+RS(P1+S(P2+SP3))

        fadd.s          &0x3F800000,%fp1        # 1+S(Q1+...)

        fmovm.x         (%sp)+,&0x30            # restore fp2,fp3

        fmov.l          %d0,%fpcr               # restore users round mode,prec
        fdiv.x          %fp1,%fp0               # last inst - possible exception set
        bra             t_inx2

NODD:
        fmov.x          %fp0,%fp1
        fmul.x          %fp0,%fp0               # S = R*R

        fmov.d          TANQ4(%pc),%fp3
        fmov.d          TANP3(%pc),%fp2

        fmul.x          %fp0,%fp3               # SQ4
        fmul.x          %fp0,%fp2               # SP3

        fadd.d          TANQ3(%pc),%fp3         # Q3+SQ4
        fadd.x          TANP2(%pc),%fp2         # P2+SP3

        fmul.x          %fp0,%fp3               # S(Q3+SQ4)
        fmul.x          %fp0,%fp2               # S(P2+SP3)

        fadd.x          TANQ2(%pc),%fp3         # Q2+S(Q3+SQ4)
        fadd.x          TANP1(%pc),%fp2         # P1+S(P2+SP3)

        fmul.x          %fp0,%fp3               # S(Q2+S(Q3+SQ4))
        fmul.x          %fp0,%fp2               # S(P1+S(P2+SP3))

        fadd.x          TANQ1(%pc),%fp3         # Q1+S(Q2+S(Q3+SQ4))
        fmul.x          %fp1,%fp2               # RS(P1+S(P2+SP3))

        fmul.x          %fp3,%fp0               # S(Q1+S(Q2+S(Q3+SQ4)))

        fadd.x          %fp2,%fp1               # R+RS(P1+S(P2+SP3))
        fadd.s          &0x3F800000,%fp0        # 1+S(Q1+...)

        fmovm.x         (%sp)+,&0x30            # restore fp2,fp3

        fmov.x          %fp1,-(%sp)
        eor.l           &0x80000000,(%sp)

        fmov.l          %d0,%fpcr               # restore users round mode,prec
        fdiv.x          (%sp)+,%fp0             # last inst - possible exception set
        bra             t_inx2

TANBORS:
#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION.
#--IF |X| < 2**(-40), RETURN X OR 1.
        cmp.l           %d1,&0x3FFF8000
        bgt.b           REDUCEX

TANSM:
        fmov.x          %fp0,-(%sp)
        fmov.l          %d0,%fpcr               # restore users round mode,prec
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          (%sp)+,%fp0             # last inst - posibble exception set
        bra             t_catch

        global          stand
#--TAN(X) = X FOR DENORMALIZED X
stand:
        bra             t_extdnrm

#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW.
#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING
#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE.
REDUCEX:
        fmovm.x         &0x3c,-(%sp)            # save {fp2-fp5}
        mov.l           %d2,-(%sp)              # save d2
        fmov.s          &0x00000000,%fp1        # fp1 = 0

#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that
#--there is a danger of unwanted overflow in first LOOP iteration.  In this
#--case, reduce argument by one remainder step to make subsequent reduction
#--safe.
        cmp.l           %d1,&0x7ffeffff         # is arg dangerously large?
        bne.b           LOOP                    # no

# yes; create 2**16383*PI/2
        mov.w           &0x7ffe,FP_SCR0_EX(%a6)
        mov.l           &0xc90fdaa2,FP_SCR0_HI(%a6)
        clr.l           FP_SCR0_LO(%a6)

# create low half of 2**16383*PI/2 at FP_SCR1
        mov.w           &0x7fdc,FP_SCR1_EX(%a6)
        mov.l           &0x85a308d3,FP_SCR1_HI(%a6)
        clr.l           FP_SCR1_LO(%a6)

        ftest.x         %fp0                    # test sign of argument
        fblt.w          red_neg

        or.b            &0x80,FP_SCR0_EX(%a6)   # positive arg
        or.b            &0x80,FP_SCR1_EX(%a6)
red_neg:
        fadd.x          FP_SCR0(%a6),%fp0       # high part of reduction is exact
        fmov.x          %fp0,%fp1               # save high result in fp1
        fadd.x          FP_SCR1(%a6),%fp0       # low part of reduction
        fsub.x          %fp0,%fp1               # determine low component of result
        fadd.x          FP_SCR1(%a6),%fp1       # fp0/fp1 are reduced argument.

#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
#--integer quotient will be stored in N
#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
LOOP:
        fmov.x          %fp0,INARG(%a6)         # +-2**K * F, 1 <= F < 2
        mov.w           INARG(%a6),%d1
        mov.l           %d1,%a1                 # save a copy of D0
        and.l           &0x00007FFF,%d1
        sub.l           &0x00003FFF,%d1         # d0 = K
        cmp.l           %d1,&28
        ble.b           LASTLOOP
CONTLOOP:
        sub.l           &27,%d1                 # d0 = L := K-27
        mov.b           &0,ENDFLAG(%a6)
        bra.b           WORK
LASTLOOP:
        clr.l           %d1                     # d0 = L := 0
        mov.b           &1,ENDFLAG(%a6)

WORK:
#--FIND THE REMAINDER OF (R,r) W.R.T.   2**L * (PI/2). L IS SO CHOSEN
#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29.

#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63),
#--2**L * (PIby2_1), 2**L * (PIby2_2)

        mov.l           &0x00003FFE,%d2         # BIASED EXP OF 2/PI
        sub.l           %d1,%d2                 # BIASED EXP OF 2**(-L)*(2/PI)

        mov.l           &0xA2F9836E,FP_SCR0_HI(%a6)
        mov.l           &0x4E44152A,FP_SCR0_LO(%a6)
        mov.w           %d2,FP_SCR0_EX(%a6)     # FP_SCR0 = 2**(-L)*(2/PI)

        fmov.x          %fp0,%fp2
        fmul.x          FP_SCR0(%a6),%fp2       # fp2 = X * 2**(-L)*(2/PI)

#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN
#--FLOATING POINT FORMAT, THE TWO FMOVE'S       FMOVE.L FP <--> N
#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT
#--(SIGN(INARG)*2**63   +       FP2) - SIGN(INARG)*2**63 WILL GIVE
#--US THE DESIRED VALUE IN FLOATING POINT.
        mov.l           %a1,%d2
        swap            %d2
        and.l           &0x80000000,%d2
        or.l            &0x5F000000,%d2         # d2 = SIGN(INARG)*2**63 IN SGL
        mov.l           %d2,TWOTO63(%a6)
        fadd.s          TWOTO63(%a6),%fp2       # THE FRACTIONAL PART OF FP1 IS ROUNDED
        fsub.s          TWOTO63(%a6),%fp2       # fp2 = N
#       fintrz.x        %fp2,%fp2

#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2
        mov.l           %d1,%d2                 # d2 = L

        add.l           &0x00003FFF,%d2         # BIASED EXP OF 2**L * (PI/2)
        mov.w           %d2,FP_SCR0_EX(%a6)
        mov.l           &0xC90FDAA2,FP_SCR0_HI(%a6)
        clr.l           FP_SCR0_LO(%a6)         # FP_SCR0 = 2**(L) * Piby2_1

        add.l           &0x00003FDD,%d1
        mov.w           %d1,FP_SCR1_EX(%a6)
        mov.l           &0x85A308D3,FP_SCR1_HI(%a6)
        clr.l           FP_SCR1_LO(%a6)         # FP_SCR1 = 2**(L) * Piby2_2

        mov.b           ENDFLAG(%a6),%d1

#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and
#--P2 = 2**(L) * Piby2_2
        fmov.x          %fp2,%fp4               # fp4 = N
        fmul.x          FP_SCR0(%a6),%fp4       # fp4 = W = N*P1
        fmov.x          %fp2,%fp5               # fp5 = N
        fmul.x          FP_SCR1(%a6),%fp5       # fp5 = w = N*P2
        fmov.x          %fp4,%fp3               # fp3 = W = N*P1

#--we want P+p = W+w  but  |p| <= half ulp of P
#--Then, we need to compute  A := R-P   and  a := r-p
        fadd.x          %fp5,%fp3               # fp3 = P
        fsub.x          %fp3,%fp4               # fp4 = W-P

        fsub.x          %fp3,%fp0               # fp0 = A := R - P
        fadd.x          %fp5,%fp4               # fp4 = p = (W-P)+w

        fmov.x          %fp0,%fp3               # fp3 = A
        fsub.x          %fp4,%fp1               # fp1 = a := r - p

#--Now we need to normalize (A,a) to  "new (R,r)" where R+r = A+a but
#--|r| <= half ulp of R.
        fadd.x          %fp1,%fp0               # fp0 = R := A+a
#--No need to calculate r if this is the last loop
        cmp.b           %d1,&0
        bgt.w           RESTORE

#--Need to calculate r
        fsub.x          %fp0,%fp3               # fp3 = A-R
        fadd.x          %fp3,%fp1               # fp1 = r := (A-R)+a
        bra.w           LOOP

RESTORE:
        fmov.l          %fp2,INT(%a6)
        mov.l           (%sp)+,%d2              # restore d2
        fmovm.x         (%sp)+,&0x3c            # restore {fp2-fp5}

        mov.l           INT(%a6),%d1
        ror.l           &1,%d1

        bra.w           TANCONT

#########################################################################
# satan():  computes the arctangent of a normalized number              #
# satand(): computes the arctangent of a denormalized number            #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = arctan(X)                                                 #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 2 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#       Step 1. If |X| >= 16 or |X| < 1/16, go to Step 5.               #
#                                                                       #
#       Step 2. Let X = sgn * 2**k * 1.xxxxxxxx...x.                    #
#               Note that k = -4, -3,..., or 3.                         #
#               Define F = sgn * 2**k * 1.xxxx1, i.e. the first 5       #
#               significant bits of X with a bit-1 attached at the 6-th #
#               bit position. Define u to be u = (X-F) / (1 + X*F).     #
#                                                                       #
#       Step 3. Approximate arctan(u) by a polynomial poly.             #
#                                                                       #
#       Step 4. Return arctan(F) + poly, arctan(F) is fetched from a    #
#               table of values calculated beforehand. Exit.            #
#                                                                       #
#       Step 5. If |X| >= 16, go to Step 7.                             #
#                                                                       #
#       Step 6. Approximate arctan(X) by an odd polynomial in X. Exit.  #
#                                                                       #
#       Step 7. Define X' = -1/X. Approximate arctan(X') by an odd      #
#               polynomial in X'.                                       #
#               Arctan(X) = sign(X)*Pi/2 + arctan(X'). Exit.            #
#                                                                       #
#########################################################################

ATANA3: long            0xBFF6687E,0x314987D8
ATANA2: long            0x4002AC69,0x34A26DB3
ATANA1: long            0xBFC2476F,0x4E1DA28E

ATANB6: long            0x3FB34444,0x7F876989
ATANB5: long            0xBFB744EE,0x7FAF45DB
ATANB4: long            0x3FBC71C6,0x46940220
ATANB3: long            0xBFC24924,0x921872F9
ATANB2: long            0x3FC99999,0x99998FA9
ATANB1: long            0xBFD55555,0x55555555

ATANC5: long            0xBFB70BF3,0x98539E6A
ATANC4: long            0x3FBC7187,0x962D1D7D
ATANC3: long            0xBFC24924,0x827107B8
ATANC2: long            0x3FC99999,0x9996263E
ATANC1: long            0xBFD55555,0x55555536

PPIBY2: long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
NPIBY2: long            0xBFFF0000,0xC90FDAA2,0x2168C235,0x00000000

PTINY:  long            0x00010000,0x80000000,0x00000000,0x00000000
NTINY:  long            0x80010000,0x80000000,0x00000000,0x00000000

ATANTBL:
        long            0x3FFB0000,0x83D152C5,0x060B7A51,0x00000000
        long            0x3FFB0000,0x8BC85445,0x65498B8B,0x00000000
        long            0x3FFB0000,0x93BE4060,0x17626B0D,0x00000000
        long            0x3FFB0000,0x9BB3078D,0x35AEC202,0x00000000
        long            0x3FFB0000,0xA3A69A52,0x5DDCE7DE,0x00000000
        long            0x3FFB0000,0xAB98E943,0x62765619,0x00000000
        long            0x3FFB0000,0xB389E502,0xF9C59862,0x00000000
        long            0x3FFB0000,0xBB797E43,0x6B09E6FB,0x00000000
        long            0x3FFB0000,0xC367A5C7,0x39E5F446,0x00000000
        long            0x3FFB0000,0xCB544C61,0xCFF7D5C6,0x00000000
        long            0x3FFB0000,0xD33F62F8,0x2488533E,0x00000000
        long            0x3FFB0000,0xDB28DA81,0x62404C77,0x00000000
        long            0x3FFB0000,0xE310A407,0x8AD34F18,0x00000000
        long            0x3FFB0000,0xEAF6B0A8,0x188EE1EB,0x00000000
        long            0x3FFB0000,0xF2DAF194,0x9DBE79D5,0x00000000
        long            0x3FFB0000,0xFABD5813,0x61D47E3E,0x00000000
        long            0x3FFC0000,0x8346AC21,0x0959ECC4,0x00000000
        long            0x3FFC0000,0x8B232A08,0x304282D8,0x00000000
        long            0x3FFC0000,0x92FB70B8,0xD29AE2F9,0x00000000
        long            0x3FFC0000,0x9ACF476F,0x5CCD1CB4,0x00000000
        long            0x3FFC0000,0xA29E7630,0x4954F23F,0x00000000
        long            0x3FFC0000,0xAA68C5D0,0x8AB85230,0x00000000
        long            0x3FFC0000,0xB22DFFFD,0x9D539F83,0x00000000
        long            0x3FFC0000,0xB9EDEF45,0x3E900EA5,0x00000000
        long            0x3FFC0000,0xC1A85F1C,0xC75E3EA5,0x00000000
        long            0x3FFC0000,0xC95D1BE8,0x28138DE6,0x00000000
        long            0x3FFC0000,0xD10BF300,0x840D2DE4,0x00000000
        long            0x3FFC0000,0xD8B4B2BA,0x6BC05E7A,0x00000000
        long            0x3FFC0000,0xE0572A6B,0xB42335F6,0x00000000
        long            0x3FFC0000,0xE7F32A70,0xEA9CAA8F,0x00000000
        long            0x3FFC0000,0xEF888432,0x64ECEFAA,0x00000000
        long            0x3FFC0000,0xF7170A28,0xECC06666,0x00000000
        long            0x3FFD0000,0x812FD288,0x332DAD32,0x00000000
        long            0x3FFD0000,0x88A8D1B1,0x218E4D64,0x00000000
        long            0x3FFD0000,0x9012AB3F,0x23E4AEE8,0x00000000
        long            0x3FFD0000,0x976CC3D4,0x11E7F1B9,0x00000000
        long            0x3FFD0000,0x9EB68949,0x3889A227,0x00000000
        long            0x3FFD0000,0xA5EF72C3,0x4487361B,0x00000000
        long            0x3FFD0000,0xAD1700BA,0xF07A7227,0x00000000
        long            0x3FFD0000,0xB42CBCFA,0xFD37EFB7,0x00000000
        long            0x3FFD0000,0xBB303A94,0x0BA80F89,0x00000000
        long            0x3FFD0000,0xC22115C6,0xFCAEBBAF,0x00000000
        long            0x3FFD0000,0xC8FEF3E6,0x86331221,0x00000000
        long            0x3FFD0000,0xCFC98330,0xB4000C70,0x00000000
        long            0x3FFD0000,0xD6807AA1,0x102C5BF9,0x00000000
        long            0x3FFD0000,0xDD2399BC,0x31252AA3,0x00000000
        long            0x3FFD0000,0xE3B2A855,0x6B8FC517,0x00000000
        long            0x3FFD0000,0xEA2D764F,0x64315989,0x00000000
        long            0x3FFD0000,0xF3BF5BF8,0xBAD1A21D,0x00000000
        long            0x3FFE0000,0x801CE39E,0x0D205C9A,0x00000000
        long            0x3FFE0000,0x8630A2DA,0xDA1ED066,0x00000000
        long            0x3FFE0000,0x8C1AD445,0xF3E09B8C,0x00000000
        long            0x3FFE0000,0x91DB8F16,0x64F350E2,0x00000000
        long            0x3FFE0000,0x97731420,0x365E538C,0x00000000
        long            0x3FFE0000,0x9CE1C8E6,0xA0B8CDBA,0x00000000
        long            0x3FFE0000,0xA22832DB,0xCADAAE09,0x00000000
        long            0x3FFE0000,0xA746F2DD,0xB7602294,0x00000000
        long            0x3FFE0000,0xAC3EC0FB,0x997DD6A2,0x00000000
        long            0x3FFE0000,0xB110688A,0xEBDC6F6A,0x00000000
        long            0x3FFE0000,0xB5BCC490,0x59ECC4B0,0x00000000
        long            0x3FFE0000,0xBA44BC7D,0xD470782F,0x00000000
        long            0x3FFE0000,0xBEA94144,0xFD049AAC,0x00000000
        long            0x3FFE0000,0xC2EB4ABB,0x661628B6,0x00000000
        long            0x3FFE0000,0xC70BD54C,0xE602EE14,0x00000000
        long            0x3FFE0000,0xCD000549,0xADEC7159,0x00000000
        long            0x3FFE0000,0xD48457D2,0xD8EA4EA3,0x00000000
        long            0x3FFE0000,0xDB948DA7,0x12DECE3B,0x00000000
        long            0x3FFE0000,0xE23855F9,0x69E8096A,0x00000000
        long            0x3FFE0000,0xE8771129,0xC4353259,0x00000000
        long            0x3FFE0000,0xEE57C16E,0x0D379C0D,0x00000000
        long            0x3FFE0000,0xF3E10211,0xA87C3779,0x00000000
        long            0x3FFE0000,0xF919039D,0x758B8D41,0x00000000
        long            0x3FFE0000,0xFE058B8F,0x64935FB3,0x00000000
        long            0x3FFF0000,0x8155FB49,0x7B685D04,0x00000000
        long            0x3FFF0000,0x83889E35,0x49D108E1,0x00000000
        long            0x3FFF0000,0x859CFA76,0x511D724B,0x00000000
        long            0x3FFF0000,0x87952ECF,0xFF8131E7,0x00000000
        long            0x3FFF0000,0x89732FD1,0x9557641B,0x00000000
        long            0x3FFF0000,0x8B38CAD1,0x01932A35,0x00000000
        long            0x3FFF0000,0x8CE7A8D8,0x301EE6B5,0x00000000
        long            0x3FFF0000,0x8F46A39E,0x2EAE5281,0x00000000
        long            0x3FFF0000,0x922DA7D7,0x91888487,0x00000000
        long            0x3FFF0000,0x94D19FCB,0xDEDF5241,0x00000000
        long            0x3FFF0000,0x973AB944,0x19D2A08B,0x00000000
        long            0x3FFF0000,0x996FF00E,0x08E10B96,0x00000000
        long            0x3FFF0000,0x9B773F95,0x12321DA7,0x00000000
        long            0x3FFF0000,0x9D55CC32,0x0F935624,0x00000000
        long            0x3FFF0000,0x9F100575,0x006CC571,0x00000000
        long            0x3FFF0000,0xA0A9C290,0xD97CC06C,0x00000000
        long            0x3FFF0000,0xA22659EB,0xEBC0630A,0x00000000
        long            0x3FFF0000,0xA388B4AF,0xF6EF0EC9,0x00000000
        long            0x3FFF0000,0xA4D35F10,0x61D292C4,0x00000000
        long            0x3FFF0000,0xA60895DC,0xFBE3187E,0x00000000
        long            0x3FFF0000,0xA72A51DC,0x7367BEAC,0x00000000
        long            0x3FFF0000,0xA83A5153,0x0956168F,0x00000000
        long            0x3FFF0000,0xA93A2007,0x7539546E,0x00000000
        long            0x3FFF0000,0xAA9E7245,0x023B2605,0x00000000
        long            0x3FFF0000,0xAC4C84BA,0x6FE4D58F,0x00000000
        long            0x3FFF0000,0xADCE4A4A,0x606B9712,0x00000000
        long            0x3FFF0000,0xAF2A2DCD,0x8D263C9C,0x00000000
        long            0x3FFF0000,0xB0656F81,0xF22265C7,0x00000000
        long            0x3FFF0000,0xB1846515,0x0F71496A,0x00000000
        long            0x3FFF0000,0xB28AAA15,0x6F9ADA35,0x00000000
        long            0x3FFF0000,0xB37B44FF,0x3766B895,0x00000000
        long            0x3FFF0000,0xB458C3DC,0xE9630433,0x00000000
        long            0x3FFF0000,0xB525529D,0x562246BD,0x00000000
        long            0x3FFF0000,0xB5E2CCA9,0x5F9D88CC,0x00000000
        long            0x3FFF0000,0xB692CADA,0x7ACA1ADA,0x00000000
        long            0x3FFF0000,0xB736AEA7,0xA6925838,0x00000000
        long            0x3FFF0000,0xB7CFAB28,0x7E9F7B36,0x00000000
        long            0x3FFF0000,0xB85ECC66,0xCB219835,0x00000000
        long            0x3FFF0000,0xB8E4FD5A,0x20A593DA,0x00000000
        long            0x3FFF0000,0xB99F41F6,0x4AFF9BB5,0x00000000
        long            0x3FFF0000,0xBA7F1E17,0x842BBE7B,0x00000000
        long            0x3FFF0000,0xBB471285,0x7637E17D,0x00000000
        long            0x3FFF0000,0xBBFABE8A,0x4788DF6F,0x00000000
        long            0x3FFF0000,0xBC9D0FAD,0x2B689D79,0x00000000
        long            0x3FFF0000,0xBD306A39,0x471ECD86,0x00000000
        long            0x3FFF0000,0xBDB6C731,0x856AF18A,0x00000000
        long            0x3FFF0000,0xBE31CAC5,0x02E80D70,0x00000000
        long            0x3FFF0000,0xBEA2D55C,0xE33194E2,0x00000000
        long            0x3FFF0000,0xBF0B10B7,0xC03128F0,0x00000000
        long            0x3FFF0000,0xBF6B7A18,0xDACB778D,0x00000000
        long            0x3FFF0000,0xBFC4EA46,0x63FA18F6,0x00000000
        long            0x3FFF0000,0xC0181BDE,0x8B89A454,0x00000000
        long            0x3FFF0000,0xC065B066,0xCFBF6439,0x00000000
        long            0x3FFF0000,0xC0AE345F,0x56340AE6,0x00000000
        long            0x3FFF0000,0xC0F22291,0x9CB9E6A7,0x00000000

        set             X,FP_SCR0
        set             XDCARE,X+2
        set             XFRAC,X+4
        set             XFRACLO,X+8

        set             ATANF,FP_SCR1
        set             ATANFHI,ATANF+4
        set             ATANFLO,ATANF+8

        global          satan
#--ENTRY POINT FOR ATAN(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
satan:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        fmov.x          %fp0,X(%a6)
        and.l           &0x7FFFFFFF,%d1

        cmp.l           %d1,&0x3FFB8000         # |X| >= 1/16?
        bge.b           ATANOK1
        bra.w           ATANSM

ATANOK1:
        cmp.l           %d1,&0x4002FFFF         # |X| < 16 ?
        ble.b           ATANMAIN
        bra.w           ATANBIG

#--THE MOST LIKELY CASE, |X| IN [1/16, 16). WE USE TABLE TECHNIQUE
#--THE IDEA IS ATAN(X) = ATAN(F) + ATAN( [X-F] / [1+XF] ).
#--SO IF F IS CHOSEN TO BE CLOSE TO X AND ATAN(F) IS STORED IN
#--A TABLE, ALL WE NEED IS TO APPROXIMATE ATAN(U) WHERE
#--U = (X-F)/(1+XF) IS SMALL (REMEMBER F IS CLOSE TO X). IT IS
#--TRUE THAT A DIVIDE IS NOW NEEDED, BUT THE APPROXIMATION FOR
#--ATAN(U) IS A VERY SHORT POLYNOMIAL AND THE INDEXING TO
#--FETCH F AND SAVING OF REGISTERS CAN BE ALL HIDED UNDER THE
#--DIVIDE. IN THE END THIS METHOD IS MUCH FASTER THAN A TRADITIONAL
#--ONE. NOTE ALSO THAT THE TRADITIONAL SCHEME THAT APPROXIMATE
#--ATAN(X) DIRECTLY WILL NEED TO USE A RATIONAL APPROXIMATION
#--(DIVISION NEEDED) ANYWAY BECAUSE A POLYNOMIAL APPROXIMATION
#--WILL INVOLVE A VERY LONG POLYNOMIAL.

#--NOW WE SEE X AS +-2^K * 1.BBBBBBB....B <- 1. + 63 BITS
#--WE CHOSE F TO BE +-2^K * 1.BBBB1
#--THAT IS IT MATCHES THE EXPONENT AND FIRST 5 BITS OF X, THE
#--SIXTH BITS IS SET TO BE 1. SINCE K = -4, -3, ..., 3, THERE
#--ARE ONLY 8 TIMES 16 = 2^7 = 128 |F|'S. SINCE ATAN(-|F|) IS
#-- -ATAN(|F|), WE NEED TO STORE ONLY ATAN(|F|).

ATANMAIN:

        and.l           &0xF8000000,XFRAC(%a6)  # FIRST 5 BITS
        or.l            &0x04000000,XFRAC(%a6)  # SET 6-TH BIT TO 1
        mov.l           &0x00000000,XFRACLO(%a6) # LOCATION OF X IS NOW F

        fmov.x          %fp0,%fp1               # FP1 IS X
        fmul.x          X(%a6),%fp1             # FP1 IS X*F, NOTE THAT X*F > 0
        fsub.x          X(%a6),%fp0             # FP0 IS X-F
        fadd.s          &0x3F800000,%fp1        # FP1 IS 1 + X*F
        fdiv.x          %fp1,%fp0               # FP0 IS U = (X-F)/(1+X*F)

#--WHILE THE DIVISION IS TAKING ITS TIME, WE FETCH ATAN(|F|)
#--CREATE ATAN(F) AND STORE IT IN ATANF, AND
#--SAVE REGISTERS FP2.

        mov.l           %d2,-(%sp)              # SAVE d2 TEMPORARILY
        mov.l           %d1,%d2                 # THE EXP AND 16 BITS OF X
        and.l           &0x00007800,%d1         # 4 VARYING BITS OF F'S FRACTION
        and.l           &0x7FFF0000,%d2         # EXPONENT OF F
        sub.l           &0x3FFB0000,%d2         # K+4
        asr.l           &1,%d2
        add.l           %d2,%d1                 # THE 7 BITS IDENTIFYING F
        asr.l           &7,%d1                  # INDEX INTO TBL OF ATAN(|F|)
        lea             ATANTBL(%pc),%a1
        add.l           %d1,%a1                 # ADDRESS OF ATAN(|F|)
        mov.l           (%a1)+,ATANF(%a6)
        mov.l           (%a1)+,ATANFHI(%a6)
        mov.l           (%a1)+,ATANFLO(%a6)     # ATANF IS NOW ATAN(|F|)
        mov.l           X(%a6),%d1              # LOAD SIGN AND EXPO. AGAIN
        and.l           &0x80000000,%d1         # SIGN(F)
        or.l            %d1,ATANF(%a6)          # ATANF IS NOW SIGN(F)*ATAN(|F|)
        mov.l           (%sp)+,%d2              # RESTORE d2

#--THAT'S ALL I HAVE TO DO FOR NOW,
#--BUT ALAS, THE DIVIDE IS STILL CRANKING!

#--U IN FP0, WE ARE NOW READY TO COMPUTE ATAN(U) AS
#--U + A1*U*V*(A2 + V*(A3 + V)), V = U*U
#--THE POLYNOMIAL MAY LOOK STRANGE, BUT IS NEVERTHELESS CORRECT.
#--THE NATURAL FORM IS U + U*V*(A1 + V*(A2 + V*A3))
#--WHAT WE HAVE HERE IS MERELY  A1 = A3, A2 = A1/A3, A3 = A2/A3.
#--THE REASON FOR THIS REARRANGEMENT IS TO MAKE THE INDEPENDENT
#--PARTS A1*U*V AND (A2 + ... STUFF) MORE LOAD-BALANCED

        fmovm.x         &0x04,-(%sp)            # save fp2

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1
        fmov.d          ATANA3(%pc),%fp2
        fadd.x          %fp1,%fp2               # A3+V
        fmul.x          %fp1,%fp2               # V*(A3+V)
        fmul.x          %fp0,%fp1               # U*V
        fadd.d          ATANA2(%pc),%fp2        # A2+V*(A3+V)
        fmul.d          ATANA1(%pc),%fp1        # A1*U*V
        fmul.x          %fp2,%fp1               # A1*U*V*(A2+V*(A3+V))
        fadd.x          %fp1,%fp0               # ATAN(U), FP1 RELEASED

        fmovm.x         (%sp)+,&0x20            # restore fp2

        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
        fadd.x          ATANF(%a6),%fp0         # ATAN(X)
        bra             t_inx2

ATANBORS:
#--|X| IS IN d0 IN COMPACT FORM. FP1, d0 SAVED.
#--FP0 IS X AND |X| <= 1/16 OR |X| >= 16.
        cmp.l           %d1,&0x3FFF8000
        bgt.w           ATANBIG                 # I.E. |X| >= 16

ATANSM:
#--|X| <= 1/16
#--IF |X| < 2^(-40), RETURN X AS ANSWER. OTHERWISE, APPROXIMATE
#--ATAN(X) BY X + X*Y*(B1+Y*(B2+Y*(B3+Y*(B4+Y*(B5+Y*B6)))))
#--WHICH IS X + X*Y*( [B1+Z*(B3+Z*B5)] + [Y*(B2+Z*(B4+Z*B6)] )
#--WHERE Y = X*X, AND Z = Y*Y.

        cmp.l           %d1,&0x3FD78000
        blt.w           ATANTINY

#--COMPUTE POLYNOMIAL
        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3

        fmul.x          %fp0,%fp0               # FPO IS Y = X*X

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # FP1 IS Z = Y*Y

        fmov.d          ATANB6(%pc),%fp2
        fmov.d          ATANB5(%pc),%fp3

        fmul.x          %fp1,%fp2               # Z*B6
        fmul.x          %fp1,%fp3               # Z*B5

        fadd.d          ATANB4(%pc),%fp2        # B4+Z*B6
        fadd.d          ATANB3(%pc),%fp3        # B3+Z*B5

        fmul.x          %fp1,%fp2               # Z*(B4+Z*B6)
        fmul.x          %fp3,%fp1               # Z*(B3+Z*B5)

        fadd.d          ATANB2(%pc),%fp2        # B2+Z*(B4+Z*B6)
        fadd.d          ATANB1(%pc),%fp1        # B1+Z*(B3+Z*B5)

        fmul.x          %fp0,%fp2               # Y*(B2+Z*(B4+Z*B6))
        fmul.x          X(%a6),%fp0             # X*Y

        fadd.x          %fp2,%fp1               # [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]

        fmul.x          %fp1,%fp0               # X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))])

        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3

        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
        fadd.x          X(%a6),%fp0
        bra             t_inx2

ATANTINY:
#--|X| < 2^(-40), ATAN(X) = X

        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          X(%a6),%fp0             # last inst - possible exception set

        bra             t_catch

ATANBIG:
#--IF |X| > 2^(100), RETURN     SIGN(X)*(PI/2 - TINY). OTHERWISE,
#--RETURN SIGN(X)*PI/2 + ATAN(-1/X).
        cmp.l           %d1,&0x40638000
        bgt.w           ATANHUGE

#--APPROXIMATE ATAN(-1/X) BY
#--X'+X'*Y*(C1+Y*(C2+Y*(C3+Y*(C4+Y*C5)))), X' = -1/X, Y = X'*X'
#--THIS CAN BE RE-WRITTEN AS
#--X'+X'*Y*( [C1+Z*(C3+Z*C5)] + [Y*(C2+Z*C4)] ), Z = Y*Y.

        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3

        fmov.s          &0xBF800000,%fp1        # LOAD -1
        fdiv.x          %fp0,%fp1               # FP1 IS -1/X

#--DIVIDE IS STILL CRANKING

        fmov.x          %fp1,%fp0               # FP0 IS X'
        fmul.x          %fp0,%fp0               # FP0 IS Y = X'*X'
        fmov.x          %fp1,X(%a6)             # X IS REALLY X'

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # FP1 IS Z = Y*Y

        fmov.d          ATANC5(%pc),%fp3
        fmov.d          ATANC4(%pc),%fp2

        fmul.x          %fp1,%fp3               # Z*C5
        fmul.x          %fp1,%fp2               # Z*B4

        fadd.d          ATANC3(%pc),%fp3        # C3+Z*C5
        fadd.d          ATANC2(%pc),%fp2        # C2+Z*C4

        fmul.x          %fp3,%fp1               # Z*(C3+Z*C5), FP3 RELEASED
        fmul.x          %fp0,%fp2               # Y*(C2+Z*C4)

        fadd.d          ATANC1(%pc),%fp1        # C1+Z*(C3+Z*C5)
        fmul.x          X(%a6),%fp0             # X'*Y

        fadd.x          %fp2,%fp1               # [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)]

        fmul.x          %fp1,%fp0               # X'*Y*([B1+Z*(B3+Z*B5)]
#                                       ...     +[Y*(B2+Z*(B4+Z*B6))])
        fadd.x          X(%a6),%fp0

        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3

        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
        tst.b           (%a0)
        bpl.b           pos_big

neg_big:
        fadd.x          NPIBY2(%pc),%fp0
        bra             t_minx2

pos_big:
        fadd.x          PPIBY2(%pc),%fp0
        bra             t_pinx2

ATANHUGE:
#--RETURN SIGN(X)*(PIBY2 - TINY) = SIGN(X)*PIBY2 - SIGN(X)*TINY
        tst.b           (%a0)
        bpl.b           pos_huge

neg_huge:
        fmov.x          NPIBY2(%pc),%fp0
        fmov.l          %d0,%fpcr
        fadd.x          PTINY(%pc),%fp0
        bra             t_minx2

pos_huge:
        fmov.x          PPIBY2(%pc),%fp0
        fmov.l          %d0,%fpcr
        fadd.x          NTINY(%pc),%fp0
        bra             t_pinx2

        global          satand
#--ENTRY POINT FOR ATAN(X) FOR DENORMALIZED ARGUMENT
satand:
        bra             t_extdnrm

#########################################################################
# sasin():  computes the inverse sine of a normalized input             #
# sasind(): computes the inverse sine of a denormalized input           #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = arcsin(X)                                                 #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       ASIN                                                            #
#       1. If |X| >= 1, go to 3.                                        #
#                                                                       #
#       2. (|X| < 1) Calculate asin(X) by                               #
#               z := sqrt( [1-X][1+X] )                                 #
#               asin(X) = atan( x / z ).                                #
#               Exit.                                                   #
#                                                                       #
#       3. If |X| > 1, go to 5.                                         #
#                                                                       #
#       4. (|X| = 1) sgn := sign(X), return asin(X) := sgn * Pi/2. Exit.#
#                                                                       #
#       5. (|X| > 1) Generate an invalid operation by 0 * infinity.     #
#               Exit.                                                   #
#                                                                       #
#########################################################################

        global          sasin
sasin:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1
        cmp.l           %d1,&0x3FFF8000
        bge.b           ASINBIG

# This catch is added here for the '060 QSP. Originally, the call to
# satan() would handle this case by causing the exception which would
# not be caught until gen_except(). Now, with the exceptions being
# detected inside of satan(), the exception would have been handled there
# instead of inside sasin() as expected.
        cmp.l           %d1,&0x3FD78000
        blt.w           ASINTINY

#--THIS IS THE USUAL CASE, |X| < 1
#--ASIN(X) = ATAN( X / SQRT( (1-X)(1+X) ) )

ASINMAIN:
        fmov.s          &0x3F800000,%fp1
        fsub.x          %fp0,%fp1               # 1-X
        fmovm.x         &0x4,-(%sp)             #  {fp2}
        fmov.s          &0x3F800000,%fp2
        fadd.x          %fp0,%fp2               # 1+X
        fmul.x          %fp2,%fp1               # (1+X)(1-X)
        fmovm.x         (%sp)+,&0x20            #  {fp2}
        fsqrt.x         %fp1                    # SQRT([1-X][1+X])
        fdiv.x          %fp1,%fp0               # X/SQRT([1-X][1+X])
        fmovm.x         &0x01,-(%sp)            # save X/SQRT(...)
        lea             (%sp),%a0               # pass ptr to X/SQRT(...)
        bsr             satan
        add.l           &0xc,%sp                # clear X/SQRT(...) from stack
        bra             t_inx2

ASINBIG:
        fabs.x          %fp0                    # |X|
        fcmp.s          %fp0,&0x3F800000
        fbgt            t_operr                 # cause an operr exception

#--|X| = 1, ASIN(X) = +- PI/2.
ASINONE:
        fmov.x          PIBY2(%pc),%fp0
        mov.l           (%a0),%d1
        and.l           &0x80000000,%d1         # SIGN BIT OF X
        or.l            &0x3F800000,%d1         # +-1 IN SGL FORMAT
        mov.l           %d1,-(%sp)              # push SIGN(X) IN SGL-FMT
        fmov.l          %d0,%fpcr
        fmul.s          (%sp)+,%fp0
        bra             t_inx2

#--|X| < 2^(-40), ATAN(X) = X
ASINTINY:
        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          (%a0),%fp0              # last inst - possible exception
        bra             t_catch

        global          sasind
#--ASIN(X) = X FOR DENORMALIZED X
sasind:
        bra             t_extdnrm

#########################################################################
# sacos():  computes the inverse cosine of a normalized input           #
# sacosd(): computes the inverse cosine of a denormalized input         #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = arccos(X)                                                 #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       ACOS                                                            #
#       1. If |X| >= 1, go to 3.                                        #
#                                                                       #
#       2. (|X| < 1) Calculate acos(X) by                               #
#               z := (1-X) / (1+X)                                      #
#               acos(X) = 2 * atan( sqrt(z) ).                          #
#               Exit.                                                   #
#                                                                       #
#       3. If |X| > 1, go to 5.                                         #
#                                                                       #
#       4. (|X| = 1) If X > 0, return 0. Otherwise, return Pi. Exit.    #
#                                                                       #
#       5. (|X| > 1) Generate an invalid operation by 0 * infinity.     #
#               Exit.                                                   #
#                                                                       #
#########################################################################

        global          sacos
sacos:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        mov.l           (%a0),%d1               # pack exp w/ upper 16 fraction
        mov.w           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1
        cmp.l           %d1,&0x3FFF8000
        bge.b           ACOSBIG

#--THIS IS THE USUAL CASE, |X| < 1
#--ACOS(X) = 2 * ATAN(  SQRT( (1-X)/(1+X) ) )

ACOSMAIN:
        fmov.s          &0x3F800000,%fp1
        fadd.x          %fp0,%fp1               # 1+X
        fneg.x          %fp0                    # -X
        fadd.s          &0x3F800000,%fp0        # 1-X
        fdiv.x          %fp1,%fp0               # (1-X)/(1+X)
        fsqrt.x         %fp0                    # SQRT((1-X)/(1+X))
        mov.l           %d0,-(%sp)              # save original users fpcr
        clr.l           %d0
        fmovm.x         &0x01,-(%sp)            # save SQRT(...) to stack
        lea             (%sp),%a0               # pass ptr to sqrt
        bsr             satan                   # ATAN(SQRT([1-X]/[1+X]))
        add.l           &0xc,%sp                # clear SQRT(...) from stack

        fmov.l          (%sp)+,%fpcr            # restore users round prec,mode
        fadd.x          %fp0,%fp0               # 2 * ATAN( STUFF )
        bra             t_pinx2

ACOSBIG:
        fabs.x          %fp0
        fcmp.s          %fp0,&0x3F800000
        fbgt            t_operr                 # cause an operr exception

#--|X| = 1, ACOS(X) = 0 OR PI
        tst.b           (%a0)                   # is X positive or negative?
        bpl.b           ACOSP1

#--X = -1
#Returns PI and inexact exception
ACOSM1:
        fmov.x          PI(%pc),%fp0            # load PI
        fmov.l          %d0,%fpcr               # load round mode,prec
        fadd.s          &0x00800000,%fp0        # add a small value
        bra             t_pinx2

ACOSP1:
        bra             ld_pzero                # answer is positive zero

        global          sacosd
#--ACOS(X) = PI/2 FOR DENORMALIZED X
sacosd:
        fmov.l          %d0,%fpcr               # load user's rnd mode/prec
        fmov.x          PIBY2(%pc),%fp0
        bra             t_pinx2

#########################################################################
# setox():    computes the exponential for a normalized input           #
# setoxd():   computes the exponential for a denormalized input         #
# setoxm1():  computes the exponential minus 1 for a normalized input   #
# setoxm1d(): computes the exponential minus 1 for a denormalized input #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = exp(X) or exp(X)-1                                        #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 0.85 ulps in 64 significant bit,  #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM and IMPLEMENTATION **************************************** #
#                                                                       #
#       setoxd                                                          #
#       ------                                                          #
#       Step 1. Set ans := 1.0                                          #
#                                                                       #
#       Step 2. Return  ans := ans + sign(X)*2^(-126). Exit.            #
#       Notes:  This will always generate one exception -- inexact.     #
#                                                                       #
#                                                                       #
#       setox                                                           #
#       -----                                                           #
#                                                                       #
#       Step 1. Filter out extreme cases of input argument.             #
#               1.1     If |X| >= 2^(-65), go to Step 1.3.              #
#               1.2     Go to Step 7.                                   #
#               1.3     If |X| < 16380 log(2), go to Step 2.            #
#               1.4     Go to Step 8.                                   #
#       Notes:  The usual case should take the branches 1.1 -> 1.3 -> 2.#
#               To avoid the use of floating-point comparisons, a       #
#               compact representation of |X| is used. This format is a #
#               32-bit integer, the upper (more significant) 16 bits    #
#               are the sign and biased exponent field of |X|; the      #
#               lower 16 bits are the 16 most significant fraction      #
#               (including the explicit bit) bits of |X|. Consequently, #
#               the comparisons in Steps 1.1 and 1.3 can be performed   #
#               by integer comparison. Note also that the constant      #
#               16380 log(2) used in Step 1.3 is also in the compact    #
#               form. Thus taking the branch to Step 2 guarantees       #
#               |X| < 16380 log(2). There is no harm to have a small    #
#               number of cases where |X| is less than, but close to,   #
#               16380 log(2) and the branch to Step 9 is taken.         #
#                                                                       #
#       Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ).      #
#               2.1     Set AdjFlag := 0 (indicates the branch 1.3 -> 2 #
#                       was taken)                                      #
#               2.2     N := round-to-nearest-integer( X * 64/log2 ).   #
#               2.3     Calculate       J = N mod 64; so J = 0,1,2,..., #
#                       or 63.                                          #
#               2.4     Calculate       M = (N - J)/64; so N = 64M + J. #
#               2.5     Calculate the address of the stored value of    #
#                       2^(J/64).                                       #
#               2.6     Create the value Scale = 2^M.                   #
#       Notes:  The calculation in 2.2 is really performed by           #
#                       Z := X * constant                               #
#                       N := round-to-nearest-integer(Z)                #
#               where                                                   #
#                       constant := single-precision( 64/log 2 ).       #
#                                                                       #
#               Using a single-precision constant avoids memory         #
#               access. Another effect of using a single-precision      #
#               "constant" is that the calculated value Z is            #
#                                                                       #
#                       Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24).      #
#                                                                       #
#               This error has to be considered later in Steps 3 and 4. #
#                                                                       #
#       Step 3. Calculate X - N*log2/64.                                #
#               3.1     R := X + N*L1,                                  #
#                               where L1 := single-precision(-log2/64). #
#               3.2     R := R + N*L2,                                  #
#                               L2 := extended-precision(-log2/64 - L1).#
#       Notes:  a) The way L1 and L2 are chosen ensures L1+L2           #
#               approximate the value -log2/64 to 88 bits of accuracy.  #
#               b) N*L1 is exact because N is no longer than 22 bits    #
#               and L1 is no longer than 24 bits.                       #
#               c) The calculation X+N*L1 is also exact due to          #
#               cancellation. Thus, R is practically X+N(L1+L2) to full #
#               64 bits.                                                #
#               d) It is important to estimate how large can |R| be     #
#               after Step 3.2.                                         #
#                                                                       #
#               N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24)     #
#               X*64/log2 (1+eps)       =       N + f,  |f| <= 0.5      #
#               X*64/log2 - N   =       f - eps*X 64/log2               #
#               X - N*log2/64   =       f*log2/64 - eps*X               #
#                                                                       #
#                                                                       #
#               Now |X| <= 16446 log2, thus                             #
#                                                                       #
#                       |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 #
#                                       <= 0.57 log2/64.                #
#                This bound will be used in Step 4.                     #
#                                                                       #
#       Step 4. Approximate exp(R)-1 by a polynomial                    #
#               p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))      #
#       Notes:  a) In order to reduce memory access, the coefficients   #
#               are made as "short" as possible: A1 (which is 1/2), A4  #
#               and A5 are single precision; A2 and A3 are double       #
#               precision.                                              #
#               b) Even with the restrictions above,                    #
#                  |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062.  #
#               Note that 0.0062 is slightly bigger than 0.57 log2/64.  #
#               c) To fully utilize the pipeline, p is separated into   #
#               two independent pieces of roughly equal complexities    #
#                       p = [ R + R*S*(A2 + S*A4) ]     +               #
#                               [ S*(A1 + S*(A3 + S*A5)) ]              #
#               where S = R*R.                                          #
#                                                                       #
#       Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by             #
#                               ans := T + ( T*p + t)                   #
#               where T and t are the stored values for 2^(J/64).       #
#       Notes:  2^(J/64) is stored as T and t where T+t approximates    #
#               2^(J/64) to roughly 85 bits; T is in extended precision #
#               and t is in single precision. Note also that T is       #
#               rounded to 62 bits so that the last two bits of T are   #
#               zero. The reason for such a special form is that T-1,   #
#               T-2, and T-8 will all be exact --- a property that will #
#               give much more accurate computation of the function     #
#               EXPM1.                                                  #
#                                                                       #
#       Step 6. Reconstruction of exp(X)                                #
#                       exp(X) = 2^M * 2^(J/64) * exp(R).               #
#               6.1     If AdjFlag = 0, go to 6.3                       #
#               6.2     ans := ans * AdjScale                           #
#               6.3     Restore the user FPCR                           #
#               6.4     Return ans := ans * Scale. Exit.                #
#       Notes:  If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R,       #
#               |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will    #
#               neither overflow nor underflow. If AdjFlag = 1, that    #
#               means that                                              #
#                       X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. #
#               Hence, exp(X) may overflow or underflow or neither.     #
#               When that is the case, AdjScale = 2^(M1) where M1 is    #
#               approximately M. Thus 6.2 will never cause              #
#               over/underflow. Possible exception in 6.4 is overflow   #
#               or underflow. The inexact exception is not generated in #
#               6.4. Although one can argue that the inexact flag       #
#               should always be raised, to simulate that exception     #
#               cost to much than the flag is worth in practical uses.  #
#                                                                       #
#       Step 7. Return 1 + X.                                           #
#               7.1     ans := X                                        #
#               7.2     Restore user FPCR.                              #
#               7.3     Return ans := 1 + ans. Exit                     #
#       Notes:  For non-zero X, the inexact exception will always be    #
#               raised by 7.3. That is the only exception raised by 7.3.#
#               Note also that we use the FMOVEM instruction to move X  #
#               in Step 7.1 to avoid unnecessary trapping. (Although    #
#               the FMOVEM may not seem relevant since X is normalized, #
#               the precaution will be useful in the library version of #
#               this code where the separate entry for denormalized     #
#               inputs will be done away with.)                         #
#                                                                       #
#       Step 8. Handle exp(X) where |X| >= 16380log2.                   #
#               8.1     If |X| > 16480 log2, go to Step 9.              #
#               (mimic 2.2 - 2.6)                                       #
#               8.2     N := round-to-integer( X * 64/log2 )            #
#               8.3     Calculate J = N mod 64, J = 0,1,...,63          #
#               8.4     K := (N-J)/64, M1 := truncate(K/2), M = K-M1,   #
#                       AdjFlag := 1.                                   #
#               8.5     Calculate the address of the stored value       #
#                       2^(J/64).                                       #
#               8.6     Create the values Scale = 2^M, AdjScale = 2^M1. #
#               8.7     Go to Step 3.                                   #
#       Notes:  Refer to notes for 2.2 - 2.6.                           #
#                                                                       #
#       Step 9. Handle exp(X), |X| > 16480 log2.                        #
#               9.1     If X < 0, go to 9.3                             #
#               9.2     ans := Huge, go to 9.4                          #
#               9.3     ans := Tiny.                                    #
#               9.4     Restore user FPCR.                              #
#               9.5     Return ans := ans * ans. Exit.                  #
#       Notes:  Exp(X) will surely overflow or underflow, depending on  #
#               X's sign. "Huge" and "Tiny" are respectively large/tiny #
#               extended-precision numbers whose square over/underflow  #
#               with an inexact result. Thus, 9.5 always raises the     #
#               inexact together with either overflow or underflow.     #
#                                                                       #
#       setoxm1d                                                        #
#       --------                                                        #
#                                                                       #
#       Step 1. Set ans := 0                                            #
#                                                                       #
#       Step 2. Return  ans := X + ans. Exit.                           #
#       Notes:  This will return X with the appropriate rounding        #
#                precision prescribed by the user FPCR.                 #
#                                                                       #
#       setoxm1                                                         #
#       -------                                                         #
#                                                                       #
#       Step 1. Check |X|                                               #
#               1.1     If |X| >= 1/4, go to Step 1.3.                  #
#               1.2     Go to Step 7.                                   #
#               1.3     If |X| < 70 log(2), go to Step 2.               #
#               1.4     Go to Step 10.                                  #
#       Notes:  The usual case should take the branches 1.1 -> 1.3 -> 2.#
#               However, it is conceivable |X| can be small very often  #
#               because EXPM1 is intended to evaluate exp(X)-1          #
#               accurately when |X| is small. For further details on    #
#               the comparisons, see the notes on Step 1 of setox.      #
#                                                                       #
#       Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ).      #
#               2.1     N := round-to-nearest-integer( X * 64/log2 ).   #
#               2.2     Calculate       J = N mod 64; so J = 0,1,2,..., #
#                       or 63.                                          #
#               2.3     Calculate       M = (N - J)/64; so N = 64M + J. #
#               2.4     Calculate the address of the stored value of    #
#                       2^(J/64).                                       #
#               2.5     Create the values Sc = 2^M and                  #
#                       OnebySc := -2^(-M).                             #
#       Notes:  See the notes on Step 2 of setox.                       #
#                                                                       #
#       Step 3. Calculate X - N*log2/64.                                #
#               3.1     R := X + N*L1,                                  #
#                               where L1 := single-precision(-log2/64). #
#               3.2     R := R + N*L2,                                  #
#                               L2 := extended-precision(-log2/64 - L1).#
#       Notes:  Applying the analysis of Step 3 of setox in this case   #
#               shows that |R| <= 0.0055 (note that |X| <= 70 log2 in   #
#               this case).                                             #
#                                                                       #
#       Step 4. Approximate exp(R)-1 by a polynomial                    #
#                       p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) #
#       Notes:  a) In order to reduce memory access, the coefficients   #
#               are made as "short" as possible: A1 (which is 1/2), A5  #
#               and A6 are single precision; A2, A3 and A4 are double   #
#               precision.                                              #
#               b) Even with the restriction above,                     #
#                       |p - (exp(R)-1)| <      |R| * 2^(-72.7)         #
#               for all |R| <= 0.0055.                                  #
#               c) To fully utilize the pipeline, p is separated into   #
#               two independent pieces of roughly equal complexity      #
#                       p = [ R*S*(A2 + S*(A4 + S*A6)) ]        +       #
#                               [ R + S*(A1 + S*(A3 + S*A5)) ]          #
#               where S = R*R.                                          #
#                                                                       #
#       Step 5. Compute 2^(J/64)*p by                                   #
#                               p := T*p                                #
#               where T and t are the stored values for 2^(J/64).       #
#       Notes:  2^(J/64) is stored as T and t where T+t approximates    #
#               2^(J/64) to roughly 85 bits; T is in extended precision #
#               and t is in single precision. Note also that T is       #
#               rounded to 62 bits so that the last two bits of T are   #
#               zero. The reason for such a special form is that T-1,   #
#               T-2, and T-8 will all be exact --- a property that will #
#               be exploited in Step 6 below. The total relative error  #
#               in p is no bigger than 2^(-67.7) compared to the final  #
#               result.                                                 #
#                                                                       #
#       Step 6. Reconstruction of exp(X)-1                              #
#                       exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ).     #
#               6.1     If M <= 63, go to Step 6.3.                     #
#               6.2     ans := T + (p + (t + OnebySc)). Go to 6.6       #
#               6.3     If M >= -3, go to 6.5.                          #
#               6.4     ans := (T + (p + t)) + OnebySc. Go to 6.6       #
#               6.5     ans := (T + OnebySc) + (p + t).                 #
#               6.6     Restore user FPCR.                              #
#               6.7     Return ans := Sc * ans. Exit.                   #
#       Notes:  The various arrangements of the expressions give        #
#               accurate evaluations.                                   #
#                                                                       #
#       Step 7. exp(X)-1 for |X| < 1/4.                                 #
#               7.1     If |X| >= 2^(-65), go to Step 9.                #
#               7.2     Go to Step 8.                                   #
#                                                                       #
#       Step 8. Calculate exp(X)-1, |X| < 2^(-65).                      #
#               8.1     If |X| < 2^(-16312), goto 8.3                   #
#               8.2     Restore FPCR; return ans := X - 2^(-16382).     #
#                       Exit.                                           #
#               8.3     X := X * 2^(140).                               #
#               8.4     Restore FPCR; ans := ans - 2^(-16382).          #
#                Return ans := ans*2^(140). Exit                        #
#       Notes:  The idea is to return "X - tiny" under the user         #
#               precision and rounding modes. To avoid unnecessary      #
#               inefficiency, we stay away from denormalized numbers    #
#               the best we can. For |X| >= 2^(-16312), the             #
#               straightforward 8.2 generates the inexact exception as  #
#               the case warrants.                                      #
#                                                                       #
#       Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial          #
#                       p = X + X*X*(B1 + X*(B2 + ... + X*B12))         #
#       Notes:  a) In order to reduce memory access, the coefficients   #
#               are made as "short" as possible: B1 (which is 1/2), B9  #
#               to B12 are single precision; B3 to B8 are double        #
#               precision; and B2 is double extended.                   #
#               b) Even with the restriction above,                     #
#                       |p - (exp(X)-1)| < |X| 2^(-70.6)                #
#               for all |X| <= 0.251.                                   #
#               Note that 0.251 is slightly bigger than 1/4.            #
#               c) To fully preserve accuracy, the polynomial is        #
#               computed as                                             #
#                       X + ( S*B1 +    Q ) where S = X*X and           #
#                       Q       =       X*S*(B2 + X*(B3 + ... + X*B12)) #
#               d) To fully utilize the pipeline, Q is separated into   #
#               two independent pieces of roughly equal complexity      #
#                       Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] +       #
#                               [ S*S*(B3 + S*(B5 + ... + S*B11)) ]     #
#                                                                       #
#       Step 10. Calculate exp(X)-1 for |X| >= 70 log 2.                #
#               10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all       #
#               practical purposes. Therefore, go to Step 1 of setox.   #
#               10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical #
#               purposes.                                               #
#               ans := -1                                               #
#               Restore user FPCR                                       #
#               Return ans := ans + 2^(-126). Exit.                     #
#       Notes:  10.2 will always create an inexact and return -1 + tiny #
#               in the user rounding precision and mode.                #
#                                                                       #
#########################################################################

L2:     long            0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000

EEXPA3: long            0x3FA55555,0x55554CC1
EEXPA2: long            0x3FC55555,0x55554A54

EM1A4:  long            0x3F811111,0x11174385
EM1A3:  long            0x3FA55555,0x55554F5A

EM1A2:  long            0x3FC55555,0x55555555,0x00000000,0x00000000

EM1B8:  long            0x3EC71DE3,0xA5774682
EM1B7:  long            0x3EFA01A0,0x19D7CB68

EM1B6:  long            0x3F2A01A0,0x1A019DF3
EM1B5:  long            0x3F56C16C,0x16C170E2

EM1B4:  long            0x3F811111,0x11111111
EM1B3:  long            0x3FA55555,0x55555555

EM1B2:  long            0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB
        long            0x00000000

TWO140: long            0x48B00000,0x00000000
TWON140:
        long            0x37300000,0x00000000

EEXPTBL:
        long            0x3FFF0000,0x80000000,0x00000000,0x00000000
        long            0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B
        long            0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9
        long            0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369
        long            0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C
        long            0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F
        long            0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729
        long            0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF
        long            0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF
        long            0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA
        long            0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051
        long            0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029
        long            0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494
        long            0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0
        long            0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D
        long            0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537
        long            0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD
        long            0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087
        long            0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818
        long            0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D
        long            0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890
        long            0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C
        long            0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05
        long            0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126
        long            0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140
        long            0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA
        long            0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A
        long            0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC
        long            0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC
        long            0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610
        long            0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90
        long            0x3FFF0000,0xB311C412,0xA9112488,0x201F678A
        long            0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13
        long            0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30
        long            0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC
        long            0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6
        long            0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70
        long            0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518
        long            0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41
        long            0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B
        long            0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568
        long            0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E
        long            0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03
        long            0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D
        long            0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4
        long            0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C
        long            0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9
        long            0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21
        long            0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F
        long            0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F
        long            0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207
        long            0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175
        long            0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B
        long            0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5
        long            0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A
        long            0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22
        long            0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945
        long            0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B
        long            0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3
        long            0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05
        long            0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19
        long            0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5
        long            0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22
        long            0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A

        set             ADJFLAG,L_SCR2
        set             SCALE,FP_SCR0
        set             ADJSCALE,FP_SCR1
        set             SC,FP_SCR0
        set             ONEBYSC,FP_SCR1

        global          setox
setox:
#--entry point for EXP(X), here X is finite, non-zero, and not NaN's

#--Step 1.
        mov.l           (%a0),%d1               # load part of input X
        and.l           &0x7FFF0000,%d1         # biased expo. of X
        cmp.l           %d1,&0x3FBE0000         # 2^(-65)
        bge.b           EXPC1                   # normal case
        bra             EXPSM

EXPC1:
#--The case |X| >= 2^(-65)
        mov.w           4(%a0),%d1              # expo. and partial sig. of |X|
        cmp.l           %d1,&0x400CB167         # 16380 log2 trunc. 16 bits
        blt.b           EXPMAIN                 # normal case
        bra             EEXPBIG

EXPMAIN:
#--Step 2.
#--This is the normal branch:   2^(-65) <= |X| < 16380 log2.
        fmov.x          (%a0),%fp0              # load input from (a0)

        fmov.x          %fp0,%fp1
        fmul.s          &0x42B8AA3B,%fp0        # 64/log2 * X
        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
        mov.l           &0,ADJFLAG(%a6)
        fmov.l          %fp0,%d1                # N = int( X * 64/log2 )
        lea             EEXPTBL(%pc),%a1
        fmov.l          %d1,%fp0                # convert to floating-format

        mov.l           %d1,L_SCR1(%a6)         # save N temporarily
        and.l           &0x3F,%d1               # D0 is J = N mod 64
        lsl.l           &4,%d1
        add.l           %d1,%a1                 # address of 2^(J/64)
        mov.l           L_SCR1(%a6),%d1
        asr.l           &6,%d1                  # D0 is M
        add.w           &0x3FFF,%d1             # biased expo. of 2^(M)
        mov.w           L2(%pc),L_SCR1(%a6)     # prefetch L2, no need in CB

EXPCONT1:
#--Step 3.
#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
#--a0 points to 2^(J/64), D0 is biased expo. of 2^(M)
        fmov.x          %fp0,%fp2
        fmul.s          &0xBC317218,%fp0        # N * L1, L1 = lead(-log2/64)
        fmul.x          L2(%pc),%fp2            # N * L2, L1+L2 = -log2/64
        fadd.x          %fp1,%fp0               # X + N*L1
        fadd.x          %fp2,%fp0               # fp0 is R, reduced arg.

#--Step 4.
#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
#--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))]

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # fp1 IS S = R*R

        fmov.s          &0x3AB60B70,%fp2        # fp2 IS A5

        fmul.x          %fp1,%fp2               # fp2 IS S*A5
        fmov.x          %fp1,%fp3
        fmul.s          &0x3C088895,%fp3        # fp3 IS S*A4

        fadd.d          EEXPA3(%pc),%fp2        # fp2 IS A3+S*A5
        fadd.d          EEXPA2(%pc),%fp3        # fp3 IS A2+S*A4

        fmul.x          %fp1,%fp2               # fp2 IS S*(A3+S*A5)
        mov.w           %d1,SCALE(%a6)          # SCALE is 2^(M) in extended
        mov.l           &0x80000000,SCALE+4(%a6)
        clr.l           SCALE+8(%a6)

        fmul.x          %fp1,%fp3               # fp3 IS S*(A2+S*A4)

        fadd.s          &0x3F000000,%fp2        # fp2 IS A1+S*(A3+S*A5)
        fmul.x          %fp0,%fp3               # fp3 IS R*S*(A2+S*A4)

        fmul.x          %fp1,%fp2               # fp2 IS S*(A1+S*(A3+S*A5))
        fadd.x          %fp3,%fp0               # fp0 IS R+R*S*(A2+S*A4),

        fmov.x          (%a1)+,%fp1             # fp1 is lead. pt. of 2^(J/64)
        fadd.x          %fp2,%fp0               # fp0 is EXP(R) - 1

#--Step 5
#--final reconstruction process
#--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) )

        fmul.x          %fp1,%fp0               # 2^(J/64)*(Exp(R)-1)
        fmovm.x         (%sp)+,&0x30            # fp2 restored {%fp2/%fp3}
        fadd.s          (%a1),%fp0              # accurate 2^(J/64)

        fadd.x          %fp1,%fp0               # 2^(J/64) + 2^(J/64)*...
        mov.l           ADJFLAG(%a6),%d1

#--Step 6
        tst.l           %d1
        beq.b           NORMAL
ADJUST:
        fmul.x          ADJSCALE(%a6),%fp0
NORMAL:
        fmov.l          %d0,%fpcr               # restore user FPCR
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.x          SCALE(%a6),%fp0         # multiply 2^(M)
        bra             t_catch

EXPSM:
#--Step 7
        fmovm.x         (%a0),&0x80             # load X
        fmov.l          %d0,%fpcr
        fadd.s          &0x3F800000,%fp0        # 1+X in user mode
        bra             t_pinx2

EEXPBIG:
#--Step 8
        cmp.l           %d1,&0x400CB27C         # 16480 log2
        bgt.b           EXP2BIG
#--Steps 8.2 -- 8.6
        fmov.x          (%a0),%fp0              # load input from (a0)

        fmov.x          %fp0,%fp1
        fmul.s          &0x42B8AA3B,%fp0        # 64/log2 * X
        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
        mov.l           &1,ADJFLAG(%a6)
        fmov.l          %fp0,%d1                # N = int( X * 64/log2 )
        lea             EEXPTBL(%pc),%a1
        fmov.l          %d1,%fp0                # convert to floating-format
        mov.l           %d1,L_SCR1(%a6)         # save N temporarily
        and.l           &0x3F,%d1               # D0 is J = N mod 64
        lsl.l           &4,%d1
        add.l           %d1,%a1                 # address of 2^(J/64)
        mov.l           L_SCR1(%a6),%d1
        asr.l           &6,%d1                  # D0 is K
        mov.l           %d1,L_SCR1(%a6)         # save K temporarily
        asr.l           &1,%d1                  # D0 is M1
        sub.l           %d1,L_SCR1(%a6)         # a1 is M
        add.w           &0x3FFF,%d1             # biased expo. of 2^(M1)
        mov.w           %d1,ADJSCALE(%a6)       # ADJSCALE := 2^(M1)
        mov.l           &0x80000000,ADJSCALE+4(%a6)
        clr.l           ADJSCALE+8(%a6)
        mov.l           L_SCR1(%a6),%d1         # D0 is M
        add.w           &0x3FFF,%d1             # biased expo. of 2^(M)
        bra.w           EXPCONT1                # go back to Step 3

EXP2BIG:
#--Step 9
        tst.b           (%a0)                   # is X positive or negative?
        bmi             t_unfl2
        bra             t_ovfl2

        global          setoxd
setoxd:
#--entry point for EXP(X), X is denormalized
        mov.l           (%a0),-(%sp)
        andi.l          &0x80000000,(%sp)
        ori.l           &0x00800000,(%sp)       # sign(X)*2^(-126)

        fmov.s          &0x3F800000,%fp0

        fmov.l          %d0,%fpcr
        fadd.s          (%sp)+,%fp0
        bra             t_pinx2

        global          setoxm1
setoxm1:
#--entry point for EXPM1(X), here X is finite, non-zero, non-NaN

#--Step 1.
#--Step 1.1
        mov.l           (%a0),%d1               # load part of input X
        and.l           &0x7FFF0000,%d1         # biased expo. of X
        cmp.l           %d1,&0x3FFD0000         # 1/4
        bge.b           EM1CON1                 # |X| >= 1/4
        bra             EM1SM

EM1CON1:
#--Step 1.3
#--The case |X| >= 1/4
        mov.w           4(%a0),%d1              # expo. and partial sig. of |X|
        cmp.l           %d1,&0x4004C215         # 70log2 rounded up to 16 bits
        ble.b           EM1MAIN                 # 1/4 <= |X| <= 70log2
        bra             EM1BIG

EM1MAIN:
#--Step 2.
#--This is the case:    1/4 <= |X| <= 70 log2.
        fmov.x          (%a0),%fp0              # load input from (a0)

        fmov.x          %fp0,%fp1
        fmul.s          &0x42B8AA3B,%fp0        # 64/log2 * X
        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
        fmov.l          %fp0,%d1                # N = int( X * 64/log2 )
        lea             EEXPTBL(%pc),%a1
        fmov.l          %d1,%fp0                # convert to floating-format

        mov.l           %d1,L_SCR1(%a6)         # save N temporarily
        and.l           &0x3F,%d1               # D0 is J = N mod 64
        lsl.l           &4,%d1
        add.l           %d1,%a1                 # address of 2^(J/64)
        mov.l           L_SCR1(%a6),%d1
        asr.l           &6,%d1                  # D0 is M
        mov.l           %d1,L_SCR1(%a6)         # save a copy of M

#--Step 3.
#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
#--a0 points to 2^(J/64), D0 and a1 both contain M
        fmov.x          %fp0,%fp2
        fmul.s          &0xBC317218,%fp0        # N * L1, L1 = lead(-log2/64)
        fmul.x          L2(%pc),%fp2            # N * L2, L1+L2 = -log2/64
        fadd.x          %fp1,%fp0               # X + N*L1
        fadd.x          %fp2,%fp0               # fp0 is R, reduced arg.
        add.w           &0x3FFF,%d1             # D0 is biased expo. of 2^M

#--Step 4.
#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6)))))
#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
#--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))]

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # fp1 IS S = R*R

        fmov.s          &0x3950097B,%fp2        # fp2 IS a6

        fmul.x          %fp1,%fp2               # fp2 IS S*A6
        fmov.x          %fp1,%fp3
        fmul.s          &0x3AB60B6A,%fp3        # fp3 IS S*A5

        fadd.d          EM1A4(%pc),%fp2         # fp2 IS A4+S*A6
        fadd.d          EM1A3(%pc),%fp3         # fp3 IS A3+S*A5
        mov.w           %d1,SC(%a6)             # SC is 2^(M) in extended
        mov.l           &0x80000000,SC+4(%a6)
        clr.l           SC+8(%a6)

        fmul.x          %fp1,%fp2               # fp2 IS S*(A4+S*A6)
        mov.l           L_SCR1(%a6),%d1         # D0 is M
        neg.w           %d1                     # D0 is -M
        fmul.x          %fp1,%fp3               # fp3 IS S*(A3+S*A5)
        add.w           &0x3FFF,%d1             # biased expo. of 2^(-M)
        fadd.d          EM1A2(%pc),%fp2         # fp2 IS A2+S*(A4+S*A6)
        fadd.s          &0x3F000000,%fp3        # fp3 IS A1+S*(A3+S*A5)

        fmul.x          %fp1,%fp2               # fp2 IS S*(A2+S*(A4+S*A6))
        or.w            &0x8000,%d1             # signed/expo. of -2^(-M)
        mov.w           %d1,ONEBYSC(%a6)        # OnebySc is -2^(-M)
        mov.l           &0x80000000,ONEBYSC+4(%a6)
        clr.l           ONEBYSC+8(%a6)
        fmul.x          %fp3,%fp1               # fp1 IS S*(A1+S*(A3+S*A5))

        fmul.x          %fp0,%fp2               # fp2 IS R*S*(A2+S*(A4+S*A6))
        fadd.x          %fp1,%fp0               # fp0 IS R+S*(A1+S*(A3+S*A5))

        fadd.x          %fp2,%fp0               # fp0 IS EXP(R)-1

        fmovm.x         (%sp)+,&0x30            # fp2 restored {%fp2/%fp3}

#--Step 5
#--Compute 2^(J/64)*p

        fmul.x          (%a1),%fp0              # 2^(J/64)*(Exp(R)-1)

#--Step 6
#--Step 6.1
        mov.l           L_SCR1(%a6),%d1         # retrieve M
        cmp.l           %d1,&63
        ble.b           MLE63
#--Step 6.2     M >= 64
        fmov.s          12(%a1),%fp1            # fp1 is t
        fadd.x          ONEBYSC(%a6),%fp1       # fp1 is t+OnebySc
        fadd.x          %fp1,%fp0               # p+(t+OnebySc), fp1 released
        fadd.x          (%a1),%fp0              # T+(p+(t+OnebySc))
        bra             EM1SCALE
MLE63:
#--Step 6.3     M <= 63
        cmp.l           %d1,&-3
        bge.b           MGEN3
MLTN3:
#--Step 6.4     M <= -4
        fadd.s          12(%a1),%fp0            # p+t
        fadd.x          (%a1),%fp0              # T+(p+t)
        fadd.x          ONEBYSC(%a6),%fp0       # OnebySc + (T+(p+t))
        bra             EM1SCALE
MGEN3:
#--Step 6.5     -3 <= M <= 63
        fmov.x          (%a1)+,%fp1             # fp1 is T
        fadd.s          (%a1),%fp0              # fp0 is p+t
        fadd.x          ONEBYSC(%a6),%fp1       # fp1 is T+OnebySc
        fadd.x          %fp1,%fp0               # (T+OnebySc)+(p+t)

EM1SCALE:
#--Step 6.6
        fmov.l          %d0,%fpcr
        fmul.x          SC(%a6),%fp0
        bra             t_inx2

EM1SM:
#--Step 7       |X| < 1/4.
        cmp.l           %d1,&0x3FBE0000         # 2^(-65)
        bge.b           EM1POLY

EM1TINY:
#--Step 8       |X| < 2^(-65)
        cmp.l           %d1,&0x00330000         # 2^(-16312)
        blt.b           EM12TINY
#--Step 8.2
        mov.l           &0x80010000,SC(%a6)     # SC is -2^(-16382)
        mov.l           &0x80000000,SC+4(%a6)
        clr.l           SC+8(%a6)
        fmov.x          (%a0),%fp0
        fmov.l          %d0,%fpcr
        mov.b           &FADD_OP,%d1            # last inst is ADD
        fadd.x          SC(%a6),%fp0
        bra             t_catch

EM12TINY:
#--Step 8.3
        fmov.x          (%a0),%fp0
        fmul.d          TWO140(%pc),%fp0
        mov.l           &0x80010000,SC(%a6)
        mov.l           &0x80000000,SC+4(%a6)
        clr.l           SC+8(%a6)
        fadd.x          SC(%a6),%fp0
        fmov.l          %d0,%fpcr
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.d          TWON140(%pc),%fp0
        bra             t_catch

EM1POLY:
#--Step 9       exp(X)-1 by a simple polynomial
        fmov.x          (%a0),%fp0              # fp0 is X
        fmul.x          %fp0,%fp0               # fp0 is S := X*X
        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
        fmov.s          &0x2F30CAA8,%fp1        # fp1 is B12
        fmul.x          %fp0,%fp1               # fp1 is S*B12
        fmov.s          &0x310F8290,%fp2        # fp2 is B11
        fadd.s          &0x32D73220,%fp1        # fp1 is B10+S*B12

        fmul.x          %fp0,%fp2               # fp2 is S*B11
        fmul.x          %fp0,%fp1               # fp1 is S*(B10 + ...

        fadd.s          &0x3493F281,%fp2        # fp2 is B9+S*...
        fadd.d          EM1B8(%pc),%fp1         # fp1 is B8+S*...

        fmul.x          %fp0,%fp2               # fp2 is S*(B9+...
        fmul.x          %fp0,%fp1               # fp1 is S*(B8+...

        fadd.d          EM1B7(%pc),%fp2         # fp2 is B7+S*...
        fadd.d          EM1B6(%pc),%fp1         # fp1 is B6+S*...

        fmul.x          %fp0,%fp2               # fp2 is S*(B7+...
        fmul.x          %fp0,%fp1               # fp1 is S*(B6+...

        fadd.d          EM1B5(%pc),%fp2         # fp2 is B5+S*...
        fadd.d          EM1B4(%pc),%fp1         # fp1 is B4+S*...

        fmul.x          %fp0,%fp2               # fp2 is S*(B5+...
        fmul.x          %fp0,%fp1               # fp1 is S*(B4+...

        fadd.d          EM1B3(%pc),%fp2         # fp2 is B3+S*...
        fadd.x          EM1B2(%pc),%fp1         # fp1 is B2+S*...

        fmul.x          %fp0,%fp2               # fp2 is S*(B3+...
        fmul.x          %fp0,%fp1               # fp1 is S*(B2+...

        fmul.x          %fp0,%fp2               # fp2 is S*S*(B3+...)
        fmul.x          (%a0),%fp1              # fp1 is X*S*(B2...

        fmul.s          &0x3F000000,%fp0        # fp0 is S*B1
        fadd.x          %fp2,%fp1               # fp1 is Q

        fmovm.x         (%sp)+,&0x30            # fp2 restored {%fp2/%fp3}

        fadd.x          %fp1,%fp0               # fp0 is S*B1+Q

        fmov.l          %d0,%fpcr
        fadd.x          (%a0),%fp0
        bra             t_inx2

EM1BIG:
#--Step 10      |X| > 70 log2
        mov.l           (%a0),%d1
        cmp.l           %d1,&0
        bgt.w           EXPC1
#--Step 10.2
        fmov.s          &0xBF800000,%fp0        # fp0 is -1
        fmov.l          %d0,%fpcr
        fadd.s          &0x00800000,%fp0        # -1 + 2^(-126)
        bra             t_minx2

        global          setoxm1d
setoxm1d:
#--entry point for EXPM1(X), here X is denormalized
#--Step 0.
        bra             t_extdnrm

#########################################################################
# sgetexp():  returns the exponent portion of the input argument.       #
#             The exponent bias is removed and the exponent value is    #
#             returned as an extended precision number in fp0.          #
# sgetexpd(): handles denormalized numbers.                             #
#                                                                       #
# sgetman():  extracts the mantissa of the input argument. The          #
#             mantissa is converted to an extended precision number w/  #
#             an exponent of $3fff and is returned in fp0. The range of #
#             the result is [1.0 - 2.0).                                #
# sgetmand(): handles denormalized numbers.                             #
#                                                                       #
# INPUT *************************************************************** #
#       a0  = pointer to extended precision input                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = exponent(X) or mantissa(X)                                #
#                                                                       #
#########################################################################

        global          sgetexp
sgetexp:
        mov.w           SRC_EX(%a0),%d0         # get the exponent
        bclr            &0xf,%d0                # clear the sign bit
        subi.w          &0x3fff,%d0             # subtract off the bias
        fmov.w          %d0,%fp0                # return exp in fp0
        blt.b           sgetexpn                # it's negative
        rts

sgetexpn:
        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
        rts

        global          sgetexpd
sgetexpd:
        bsr.l           norm                    # normalize
        neg.w           %d0                     # new exp = -(shft amt)
        subi.w          &0x3fff,%d0             # subtract off the bias
        fmov.w          %d0,%fp0                # return exp in fp0
        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
        rts

        global          sgetman
sgetman:
        mov.w           SRC_EX(%a0),%d0         # get the exp
        ori.w           &0x7fff,%d0             # clear old exp
        bclr            &0xe,%d0                # make it the new exp +-3fff

# here, we build the result in a tmp location so as not to disturb the input
        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6) # copy to tmp loc
        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6) # copy to tmp loc
        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
        fmov.x          FP_SCR0(%a6),%fp0       # put new value back in fp0
        bmi.b           sgetmann                # it's negative
        rts

sgetmann:
        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
        rts

#
# For denormalized numbers, shift the mantissa until the j-bit = 1,
# then load the exponent with +/1 $3fff.
#
        global          sgetmand
sgetmand:
        bsr.l           norm                    # normalize exponent
        bra.b           sgetman

#########################################################################
# scosh():  computes the hyperbolic cosine of a normalized input        #
# scoshd(): computes the hyperbolic cosine of a denormalized input      #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = cosh(X)                                                   #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       COSH                                                            #
#       1. If |X| > 16380 log2, go to 3.                                #
#                                                                       #
#       2. (|X| <= 16380 log2) Cosh(X) is obtained by the formulae      #
#               y = |X|, z = exp(Y), and                                #
#               cosh(X) = (1/2)*( z + 1/z ).                            #
#               Exit.                                                   #
#                                                                       #
#       3. (|X| > 16380 log2). If |X| > 16480 log2, go to 5.            #
#                                                                       #
#       4. (16380 log2 < |X| <= 16480 log2)                             #
#               cosh(X) = sign(X) * exp(|X|)/2.                         #
#               However, invoking exp(|X|) may cause premature          #
#               overflow. Thus, we calculate sinh(X) as follows:        #
#               Y       := |X|                                          #
#               Fact    :=      2**(16380)                              #
#               Y'      := Y - 16381 log2                               #
#               cosh(X) := Fact * exp(Y').                              #
#               Exit.                                                   #
#                                                                       #
#       5. (|X| > 16480 log2) sinh(X) must overflow. Return             #
#               Huge*Huge to generate overflow and an infinity with     #
#               the appropriate sign. Huge is the largest finite number #
#               in extended format. Exit.                               #
#                                                                       #
#########################################################################

TWO16380:
        long            0x7FFB0000,0x80000000,0x00000000,0x00000000

        global          scosh
scosh:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1
        cmp.l           %d1,&0x400CB167
        bgt.b           COSHBIG

#--THIS IS THE USUAL CASE, |X| < 16380 LOG2
#--COSH(X) = (1/2) * ( EXP(X) + 1/EXP(X) )

        fabs.x          %fp0                    # |X|

        mov.l           %d0,-(%sp)
        clr.l           %d0
        fmovm.x         &0x01,-(%sp)            # save |X| to stack
        lea             (%sp),%a0               # pass ptr to |X|
        bsr             setox                   # FP0 IS EXP(|X|)
        add.l           &0xc,%sp                # erase |X| from stack
        fmul.s          &0x3F000000,%fp0        # (1/2)EXP(|X|)
        mov.l           (%sp)+,%d0

        fmov.s          &0x3E800000,%fp1        # (1/4)
        fdiv.x          %fp0,%fp1               # 1/(2 EXP(|X|))

        fmov.l          %d0,%fpcr
        mov.b           &FADD_OP,%d1            # last inst is ADD
        fadd.x          %fp1,%fp0
        bra             t_catch

COSHBIG:
        cmp.l           %d1,&0x400CB2B3
        bgt.b           COSHHUGE

        fabs.x          %fp0
        fsub.d          T1(%pc),%fp0            # (|X|-16381LOG2_LEAD)
        fsub.d          T2(%pc),%fp0            # |X| - 16381 LOG2, ACCURATE

        mov.l           %d0,-(%sp)
        clr.l           %d0
        fmovm.x         &0x01,-(%sp)            # save fp0 to stack
        lea             (%sp),%a0               # pass ptr to fp0
        bsr             setox
        add.l           &0xc,%sp                # clear fp0 from stack
        mov.l           (%sp)+,%d0

        fmov.l          %d0,%fpcr
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.x          TWO16380(%pc),%fp0
        bra             t_catch

COSHHUGE:
        bra             t_ovfl2

        global          scoshd
#--COSH(X) = 1 FOR DENORMALIZED X
scoshd:
        fmov.s          &0x3F800000,%fp0

        fmov.l          %d0,%fpcr
        fadd.s          &0x00800000,%fp0
        bra             t_pinx2

#########################################################################
# ssinh():  computes the hyperbolic sine of a normalized input          #
# ssinhd(): computes the hyperbolic sine of a denormalized input        #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = sinh(X)                                                   #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       SINH                                                            #
#       1. If |X| > 16380 log2, go to 3.                                #
#                                                                       #
#       2. (|X| <= 16380 log2) Sinh(X) is obtained by the formula       #
#               y = |X|, sgn = sign(X), and z = expm1(Y),               #
#               sinh(X) = sgn*(1/2)*( z + z/(1+z) ).                    #
#          Exit.                                                        #
#                                                                       #
#       3. If |X| > 16480 log2, go to 5.                                #
#                                                                       #
#       4. (16380 log2 < |X| <= 16480 log2)                             #
#               sinh(X) = sign(X) * exp(|X|)/2.                         #
#          However, invoking exp(|X|) may cause premature overflow.     #
#          Thus, we calculate sinh(X) as follows:                       #
#             Y       := |X|                                            #
#             sgn     := sign(X)                                        #
#             sgnFact := sgn * 2**(16380)                               #
#             Y'      := Y - 16381 log2                                 #
#             sinh(X) := sgnFact * exp(Y').                             #
#          Exit.                                                        #
#                                                                       #
#       5. (|X| > 16480 log2) sinh(X) must overflow. Return             #
#          sign(X)*Huge*Huge to generate overflow and an infinity with  #
#          the appropriate sign. Huge is the largest finite number in   #
#          extended format. Exit.                                       #
#                                                                       #
#########################################################################

        global          ssinh
ssinh:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        mov.l           %d1,%a1                 # save (compacted) operand
        and.l           &0x7FFFFFFF,%d1
        cmp.l           %d1,&0x400CB167
        bgt.b           SINHBIG

#--THIS IS THE USUAL CASE, |X| < 16380 LOG2
#--Y = |X|, Z = EXPM1(Y), SINH(X) = SIGN(X)*(1/2)*( Z + Z/(1+Z) )

        fabs.x          %fp0                    # Y = |X|

        movm.l          &0x8040,-(%sp)          # {a1/d0}
        fmovm.x         &0x01,-(%sp)            # save Y on stack
        lea             (%sp),%a0               # pass ptr to Y
        clr.l           %d0
        bsr             setoxm1                 # FP0 IS Z = EXPM1(Y)
        add.l           &0xc,%sp                # clear Y from stack
        fmov.l          &0,%fpcr
        movm.l          (%sp)+,&0x0201          # {a1/d0}

        fmov.x          %fp0,%fp1
        fadd.s          &0x3F800000,%fp1        # 1+Z
        fmov.x          %fp0,-(%sp)
        fdiv.x          %fp1,%fp0               # Z/(1+Z)
        mov.l           %a1,%d1
        and.l           &0x80000000,%d1
        or.l            &0x3F000000,%d1
        fadd.x          (%sp)+,%fp0
        mov.l           %d1,-(%sp)

        fmov.l          %d0,%fpcr
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.s          (%sp)+,%fp0             # last fp inst - possible exceptions set
        bra             t_catch

SINHBIG:
        cmp.l           %d1,&0x400CB2B3
        bgt             t_ovfl
        fabs.x          %fp0
        fsub.d          T1(%pc),%fp0            # (|X|-16381LOG2_LEAD)
        mov.l           &0,-(%sp)
        mov.l           &0x80000000,-(%sp)
        mov.l           %a1,%d1
        and.l           &0x80000000,%d1
        or.l            &0x7FFB0000,%d1
        mov.l           %d1,-(%sp)              # EXTENDED FMT
        fsub.d          T2(%pc),%fp0            # |X| - 16381 LOG2, ACCURATE

        mov.l           %d0,-(%sp)
        clr.l           %d0
        fmovm.x         &0x01,-(%sp)            # save fp0 on stack
        lea             (%sp),%a0               # pass ptr to fp0
        bsr             setox
        add.l           &0xc,%sp                # clear fp0 from stack

        mov.l           (%sp)+,%d0
        fmov.l          %d0,%fpcr
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.x          (%sp)+,%fp0             # possible exception
        bra             t_catch

        global          ssinhd
#--SINH(X) = X FOR DENORMALIZED X
ssinhd:
        bra             t_extdnrm

#########################################################################
# stanh():  computes the hyperbolic tangent of a normalized input       #
# stanhd(): computes the hyperbolic tangent of a denormalized input     #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = tanh(X)                                                   #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       TANH                                                            #
#       1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3.            #
#                                                                       #
#       2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by           #
#               sgn := sign(X), y := 2|X|, z := expm1(Y), and           #
#               tanh(X) = sgn*( z/(2+z) ).                              #
#               Exit.                                                   #
#                                                                       #
#       3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1,          #
#               go to 7.                                                #
#                                                                       #
#       4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6.              #
#                                                                       #
#       5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by           #
#               sgn := sign(X), y := 2|X|, z := exp(Y),                 #
#               tanh(X) = sgn - [ sgn*2/(1+z) ].                        #
#               Exit.                                                   #
#                                                                       #
#       6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we  #
#               calculate Tanh(X) by                                    #
#               sgn := sign(X), Tiny := 2**(-126),                      #
#               tanh(X) := sgn - sgn*Tiny.                              #
#               Exit.                                                   #
#                                                                       #
#       7. (|X| < 2**(-40)). Tanh(X) = X.       Exit.                   #
#                                                                       #
#########################################################################

        set             X,FP_SCR0
        set             XFRAC,X+4

        set             SGN,L_SCR3

        set             V,FP_SCR0

        global          stanh
stanh:
        fmov.x          (%a0),%fp0              # LOAD INPUT

        fmov.x          %fp0,X(%a6)
        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        mov.l           %d1,X(%a6)
        and.l           &0x7FFFFFFF,%d1
        cmp.l           %d1, &0x3fd78000        # is |X| < 2^(-40)?
        blt.w           TANHBORS                # yes
        cmp.l           %d1, &0x3fffddce        # is |X| > (5/2)LOG2?
        bgt.w           TANHBORS                # yes

#--THIS IS THE USUAL CASE
#--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2).

        mov.l           X(%a6),%d1
        mov.l           %d1,SGN(%a6)
        and.l           &0x7FFF0000,%d1
        add.l           &0x00010000,%d1         # EXPONENT OF 2|X|
        mov.l           %d1,X(%a6)
        and.l           &0x80000000,SGN(%a6)
        fmov.x          X(%a6),%fp0             # FP0 IS Y = 2|X|

        mov.l           %d0,-(%sp)
        clr.l           %d0
        fmovm.x         &0x1,-(%sp)             # save Y on stack
        lea             (%sp),%a0               # pass ptr to Y
        bsr             setoxm1                 # FP0 IS Z = EXPM1(Y)
        add.l           &0xc,%sp                # clear Y from stack
        mov.l           (%sp)+,%d0

        fmov.x          %fp0,%fp1
        fadd.s          &0x40000000,%fp1        # Z+2
        mov.l           SGN(%a6),%d1
        fmov.x          %fp1,V(%a6)
        eor.l           %d1,V(%a6)

        fmov.l          %d0,%fpcr               # restore users round prec,mode
        fdiv.x          V(%a6),%fp0
        bra             t_inx2

TANHBORS:
        cmp.l           %d1,&0x3FFF8000
        blt.w           TANHSM

        cmp.l           %d1,&0x40048AA1
        bgt.w           TANHHUGE

#-- (5/2) LOG2 < |X| < 50 LOG2,
#--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X),
#--TANH(X) = SGN -      SGN*2/[EXP(Y)+1].

        mov.l           X(%a6),%d1
        mov.l           %d1,SGN(%a6)
        and.l           &0x7FFF0000,%d1
        add.l           &0x00010000,%d1         # EXPO OF 2|X|
        mov.l           %d1,X(%a6)              # Y = 2|X|
        and.l           &0x80000000,SGN(%a6)
        mov.l           SGN(%a6),%d1
        fmov.x          X(%a6),%fp0             # Y = 2|X|

        mov.l           %d0,-(%sp)
        clr.l           %d0
        fmovm.x         &0x01,-(%sp)            # save Y on stack
        lea             (%sp),%a0               # pass ptr to Y
        bsr             setox                   # FP0 IS EXP(Y)
        add.l           &0xc,%sp                # clear Y from stack
        mov.l           (%sp)+,%d0
        mov.l           SGN(%a6),%d1
        fadd.s          &0x3F800000,%fp0        # EXP(Y)+1

        eor.l           &0xC0000000,%d1         # -SIGN(X)*2
        fmov.s          %d1,%fp1                # -SIGN(X)*2 IN SGL FMT
        fdiv.x          %fp0,%fp1               # -SIGN(X)2 / [EXP(Y)+1 ]

        mov.l           SGN(%a6),%d1
        or.l            &0x3F800000,%d1         # SGN
        fmov.s          %d1,%fp0                # SGN IN SGL FMT

        fmov.l          %d0,%fpcr               # restore users round prec,mode
        mov.b           &FADD_OP,%d1            # last inst is ADD
        fadd.x          %fp1,%fp0
        bra             t_inx2

TANHSM:
        fmov.l          %d0,%fpcr               # restore users round prec,mode
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          X(%a6),%fp0             # last inst - possible exception set
        bra             t_catch

#---RETURN SGN(X) - SGN(X)EPS
TANHHUGE:
        mov.l           X(%a6),%d1
        and.l           &0x80000000,%d1
        or.l            &0x3F800000,%d1
        fmov.s          %d1,%fp0
        and.l           &0x80000000,%d1
        eor.l           &0x80800000,%d1         # -SIGN(X)*EPS

        fmov.l          %d0,%fpcr               # restore users round prec,mode
        fadd.s          %d1,%fp0
        bra             t_inx2

        global          stanhd
#--TANH(X) = X FOR DENORMALIZED X
stanhd:
        bra             t_extdnrm

#########################################################################
# slogn():    computes the natural logarithm of a normalized input      #
# slognd():   computes the natural logarithm of a denormalized input    #
# slognp1():  computes the log(1+X) of a normalized input               #
# slognp1d(): computes the log(1+X) of a denormalized input             #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = log(X) or log(1+X)                                        #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 2 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#       LOGN:                                                           #
#       Step 1. If |X-1| < 1/16, approximate log(X) by an odd           #
#               polynomial in u, where u = 2(X-1)/(X+1). Otherwise,     #
#               move on to Step 2.                                      #
#                                                                       #
#       Step 2. X = 2**k * Y where 1 <= Y < 2. Define F to be the first #
#               seven significant bits of Y plus 2**(-7), i.e.          #
#               F = 1.xxxxxx1 in base 2 where the six "x" match those   #
#               of Y. Note that |Y-F| <= 2**(-7).                       #
#                                                                       #
#       Step 3. Define u = (Y-F)/F. Approximate log(1+u) by a           #
#               polynomial in u, log(1+u) = poly.                       #
#                                                                       #
#       Step 4. Reconstruct                                             #
#               log(X) = log( 2**k * Y ) = k*log(2) + log(F) + log(1+u) #
#               by k*log(2) + (log(F) + poly). The values of log(F) are #
#               calculated beforehand and stored in the program.        #
#                                                                       #
#       lognp1:                                                         #
#       Step 1: If |X| < 1/16, approximate log(1+X) by an odd           #
#               polynomial in u where u = 2X/(2+X). Otherwise, move on  #
#               to Step 2.                                              #
#                                                                       #
#       Step 2: Let 1+X = 2**k * Y, where 1 <= Y < 2. Define F as done  #
#               in Step 2 of the algorithm for LOGN and compute         #
#               log(1+X) as k*log(2) + log(F) + poly where poly         #
#               approximates log(1+u), u = (Y-F)/F.                     #
#                                                                       #
#       Implementation Notes:                                           #
#       Note 1. There are 64 different possible values for F, thus 64   #
#               log(F)'s need to be tabulated. Moreover, the values of  #
#               1/F are also tabulated so that the division in (Y-F)/F  #
#               can be performed by a multiplication.                   #
#                                                                       #
#       Note 2. In Step 2 of lognp1, in order to preserved accuracy,    #
#               the value Y-F has to be calculated carefully when       #
#               1/2 <= X < 3/2.                                         #
#                                                                       #
#       Note 3. To fully exploit the pipeline, polynomials are usually  #
#               separated into two parts evaluated independently before #
#               being added up.                                         #
#                                                                       #
#########################################################################
LOGOF2:
        long            0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000

one:
        long            0x3F800000
zero:
        long            0x00000000
infty:
        long            0x7F800000
negone:
        long            0xBF800000

LOGA6:
        long            0x3FC2499A,0xB5E4040B
LOGA5:
        long            0xBFC555B5,0x848CB7DB

LOGA4:
        long            0x3FC99999,0x987D8730
LOGA3:
        long            0xBFCFFFFF,0xFF6F7E97

LOGA2:
        long            0x3FD55555,0x555555A4
LOGA1:
        long            0xBFE00000,0x00000008

LOGB5:
        long            0x3F175496,0xADD7DAD6
LOGB4:
        long            0x3F3C71C2,0xFE80C7E0

LOGB3:
        long            0x3F624924,0x928BCCFF
LOGB2:
        long            0x3F899999,0x999995EC

LOGB1:
        long            0x3FB55555,0x55555555
TWO:
        long            0x40000000,0x00000000

LTHOLD:
        long            0x3f990000,0x80000000,0x00000000,0x00000000

LOGTBL:
        long            0x3FFE0000,0xFE03F80F,0xE03F80FE,0x00000000
        long            0x3FF70000,0xFF015358,0x833C47E2,0x00000000
        long            0x3FFE0000,0xFA232CF2,0x52138AC0,0x00000000
        long            0x3FF90000,0xBDC8D83E,0xAD88D549,0x00000000
        long            0x3FFE0000,0xF6603D98,0x0F6603DA,0x00000000
        long            0x3FFA0000,0x9CF43DCF,0xF5EAFD48,0x00000000
        long            0x3FFE0000,0xF2B9D648,0x0F2B9D65,0x00000000
        long            0x3FFA0000,0xDA16EB88,0xCB8DF614,0x00000000
        long            0x3FFE0000,0xEF2EB71F,0xC4345238,0x00000000
        long            0x3FFB0000,0x8B29B775,0x1BD70743,0x00000000
        long            0x3FFE0000,0xEBBDB2A5,0xC1619C8C,0x00000000
        long            0x3FFB0000,0xA8D839F8,0x30C1FB49,0x00000000
        long            0x3FFE0000,0xE865AC7B,0x7603A197,0x00000000
        long            0x3FFB0000,0xC61A2EB1,0x8CD907AD,0x00000000
        long            0x3FFE0000,0xE525982A,0xF70C880E,0x00000000
        long            0x3FFB0000,0xE2F2A47A,0xDE3A18AF,0x00000000
        long            0x3FFE0000,0xE1FC780E,0x1FC780E2,0x00000000
        long            0x3FFB0000,0xFF64898E,0xDF55D551,0x00000000
        long            0x3FFE0000,0xDEE95C4C,0xA037BA57,0x00000000
        long            0x3FFC0000,0x8DB956A9,0x7B3D0148,0x00000000
        long            0x3FFE0000,0xDBEB61EE,0xD19C5958,0x00000000
        long            0x3FFC0000,0x9B8FE100,0xF47BA1DE,0x00000000
        long            0x3FFE0000,0xD901B203,0x6406C80E,0x00000000
        long            0x3FFC0000,0xA9372F1D,0x0DA1BD17,0x00000000
        long            0x3FFE0000,0xD62B80D6,0x2B80D62C,0x00000000
        long            0x3FFC0000,0xB6B07F38,0xCE90E46B,0x00000000
        long            0x3FFE0000,0xD3680D36,0x80D3680D,0x00000000
        long            0x3FFC0000,0xC3FD0329,0x06488481,0x00000000
        long            0x3FFE0000,0xD0B69FCB,0xD2580D0B,0x00000000
        long            0x3FFC0000,0xD11DE0FF,0x15AB18CA,0x00000000
        long            0x3FFE0000,0xCE168A77,0x25080CE1,0x00000000
        long            0x3FFC0000,0xDE1433A1,0x6C66B150,0x00000000
        long            0x3FFE0000,0xCB8727C0,0x65C393E0,0x00000000
        long            0x3FFC0000,0xEAE10B5A,0x7DDC8ADD,0x00000000
        long            0x3FFE0000,0xC907DA4E,0x871146AD,0x00000000
        long            0x3FFC0000,0xF7856E5E,0xE2C9B291,0x00000000
        long            0x3FFE0000,0xC6980C69,0x80C6980C,0x00000000
        long            0x3FFD0000,0x82012CA5,0xA68206D7,0x00000000
        long            0x3FFE0000,0xC4372F85,0x5D824CA6,0x00000000
        long            0x3FFD0000,0x882C5FCD,0x7256A8C5,0x00000000
        long            0x3FFE0000,0xC1E4BBD5,0x95F6E947,0x00000000
        long            0x3FFD0000,0x8E44C60B,0x4CCFD7DE,0x00000000
        long            0x3FFE0000,0xBFA02FE8,0x0BFA02FF,0x00000000
        long            0x3FFD0000,0x944AD09E,0xF4351AF6,0x00000000
        long            0x3FFE0000,0xBD691047,0x07661AA3,0x00000000
        long            0x3FFD0000,0x9A3EECD4,0xC3EAA6B2,0x00000000
        long            0x3FFE0000,0xBB3EE721,0xA54D880C,0x00000000
        long            0x3FFD0000,0xA0218434,0x353F1DE8,0x00000000
        long            0x3FFE0000,0xB92143FA,0x36F5E02E,0x00000000
        long            0x3FFD0000,0xA5F2FCAB,0xBBC506DA,0x00000000
        long            0x3FFE0000,0xB70FBB5A,0x19BE3659,0x00000000
        long            0x3FFD0000,0xABB3B8BA,0x2AD362A5,0x00000000
        long            0x3FFE0000,0xB509E68A,0x9B94821F,0x00000000
        long            0x3FFD0000,0xB1641795,0xCE3CA97B,0x00000000
        long            0x3FFE0000,0xB30F6352,0x8917C80B,0x00000000
        long            0x3FFD0000,0xB7047551,0x5D0F1C61,0x00000000
        long            0x3FFE0000,0xB11FD3B8,0x0B11FD3C,0x00000000
        long            0x3FFD0000,0xBC952AFE,0xEA3D13E1,0x00000000
        long            0x3FFE0000,0xAF3ADDC6,0x80AF3ADE,0x00000000
        long            0x3FFD0000,0xC2168ED0,0xF458BA4A,0x00000000
        long            0x3FFE0000,0xAD602B58,0x0AD602B6,0x00000000
        long            0x3FFD0000,0xC788F439,0xB3163BF1,0x00000000
        long            0x3FFE0000,0xAB8F69E2,0x8359CD11,0x00000000
        long            0x3FFD0000,0xCCECAC08,0xBF04565D,0x00000000
        long            0x3FFE0000,0xA9C84A47,0xA07F5638,0x00000000
        long            0x3FFD0000,0xD2420487,0x2DD85160,0x00000000
        long            0x3FFE0000,0xA80A80A8,0x0A80A80B,0x00000000
        long            0x3FFD0000,0xD7894992,0x3BC3588A,0x00000000
        long            0x3FFE0000,0xA655C439,0x2D7B73A8,0x00000000
        long            0x3FFD0000,0xDCC2C4B4,0x9887DACC,0x00000000
        long            0x3FFE0000,0xA4A9CF1D,0x96833751,0x00000000
        long            0x3FFD0000,0xE1EEBD3E,0x6D6A6B9E,0x00000000
        long            0x3FFE0000,0xA3065E3F,0xAE7CD0E0,0x00000000
        long            0x3FFD0000,0xE70D785C,0x2F9F5BDC,0x00000000
        long            0x3FFE0000,0xA16B312E,0xA8FC377D,0x00000000
        long            0x3FFD0000,0xEC1F392C,0x5179F283,0x00000000
        long            0x3FFE0000,0x9FD809FD,0x809FD80A,0x00000000
        long            0x3FFD0000,0xF12440D3,0xE36130E6,0x00000000
        long            0x3FFE0000,0x9E4CAD23,0xDD5F3A20,0x00000000
        long            0x3FFD0000,0xF61CCE92,0x346600BB,0x00000000
        long            0x3FFE0000,0x9CC8E160,0xC3FB19B9,0x00000000
        long            0x3FFD0000,0xFB091FD3,0x8145630A,0x00000000
        long            0x3FFE0000,0x9B4C6F9E,0xF03A3CAA,0x00000000
        long            0x3FFD0000,0xFFE97042,0xBFA4C2AD,0x00000000
        long            0x3FFE0000,0x99D722DA,0xBDE58F06,0x00000000
        long            0x3FFE0000,0x825EFCED,0x49369330,0x00000000
        long            0x3FFE0000,0x9868C809,0x868C8098,0x00000000
        long            0x3FFE0000,0x84C37A7A,0xB9A905C9,0x00000000
        long            0x3FFE0000,0x97012E02,0x5C04B809,0x00000000
        long            0x3FFE0000,0x87224C2E,0x8E645FB7,0x00000000
        long            0x3FFE0000,0x95A02568,0x095A0257,0x00000000
        long            0x3FFE0000,0x897B8CAC,0x9F7DE298,0x00000000
        long            0x3FFE0000,0x94458094,0x45809446,0x00000000
        long            0x3FFE0000,0x8BCF55DE,0xC4CD05FE,0x00000000
        long            0x3FFE0000,0x92F11384,0x0497889C,0x00000000
        long            0x3FFE0000,0x8E1DC0FB,0x89E125E5,0x00000000
        long            0x3FFE0000,0x91A2B3C4,0xD5E6F809,0x00000000
        long            0x3FFE0000,0x9066E68C,0x955B6C9B,0x00000000
        long            0x3FFE0000,0x905A3863,0x3E06C43B,0x00000000
        long            0x3FFE0000,0x92AADE74,0xC7BE59E0,0x00000000
        long            0x3FFE0000,0x8F1779D9,0xFDC3A219,0x00000000
        long            0x3FFE0000,0x94E9BFF6,0x15845643,0x00000000
        long            0x3FFE0000,0x8DDA5202,0x37694809,0x00000000
        long            0x3FFE0000,0x9723A1B7,0x20134203,0x00000000
        long            0x3FFE0000,0x8CA29C04,0x6514E023,0x00000000
        long            0x3FFE0000,0x995899C8,0x90EB8990,0x00000000
        long            0x3FFE0000,0x8B70344A,0x139BC75A,0x00000000
        long            0x3FFE0000,0x9B88BDAA,0x3A3DAE2F,0x00000000
        long            0x3FFE0000,0x8A42F870,0x5669DB46,0x00000000
        long            0x3FFE0000,0x9DB4224F,0xFFE1157C,0x00000000
        long            0x3FFE0000,0x891AC73A,0xE9819B50,0x00000000
        long            0x3FFE0000,0x9FDADC26,0x8B7A12DA,0x00000000
        long            0x3FFE0000,0x87F78087,0xF78087F8,0x00000000
        long            0x3FFE0000,0xA1FCFF17,0xCE733BD4,0x00000000
        long            0x3FFE0000,0x86D90544,0x7A34ACC6,0x00000000
        long            0x3FFE0000,0xA41A9E8F,0x5446FB9F,0x00000000
        long            0x3FFE0000,0x85BF3761,0x2CEE3C9B,0x00000000
        long            0x3FFE0000,0xA633CD7E,0x6771CD8B,0x00000000
        long            0x3FFE0000,0x84A9F9C8,0x084A9F9D,0x00000000
        long            0x3FFE0000,0xA8489E60,0x0B435A5E,0x00000000
        long            0x3FFE0000,0x83993052,0x3FBE3368,0x00000000
        long            0x3FFE0000,0xAA59233C,0xCCA4BD49,0x00000000
        long            0x3FFE0000,0x828CBFBE,0xB9A020A3,0x00000000
        long            0x3FFE0000,0xAC656DAE,0x6BCC4985,0x00000000
        long            0x3FFE0000,0x81848DA8,0xFAF0D277,0x00000000
        long            0x3FFE0000,0xAE6D8EE3,0x60BB2468,0x00000000
        long            0x3FFE0000,0x80808080,0x80808081,0x00000000
        long            0x3FFE0000,0xB07197A2,0x3C46C654,0x00000000

        set             ADJK,L_SCR1

        set             X,FP_SCR0
        set             XDCARE,X+2
        set             XFRAC,X+4

        set             F,FP_SCR1
        set             FFRAC,F+4

        set             KLOG2,FP_SCR0

        set             SAVEU,FP_SCR0

        global          slogn
#--ENTRY POINT FOR LOG(X) FOR X FINITE, NON-ZERO, NOT NAN'S
slogn:
        fmov.x          (%a0),%fp0              # LOAD INPUT
        mov.l           &0x00000000,ADJK(%a6)

LOGBGN:
#--FPCR SAVED AND CLEARED, INPUT IS 2^(ADJK)*FP0, FP0 CONTAINS
#--A FINITE, NON-ZERO, NORMALIZED NUMBER.

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1

        mov.l           (%a0),X(%a6)
        mov.l           4(%a0),X+4(%a6)
        mov.l           8(%a0),X+8(%a6)

        cmp.l           %d1,&0                   # CHECK IF X IS NEGATIVE
        blt.w           LOGNEG                  # LOG OF NEGATIVE ARGUMENT IS INVALID
# X IS POSITIVE, CHECK IF X IS NEAR 1
        cmp.l           %d1,&0x3ffef07d         # IS X < 15/16?
        blt.b           LOGMAIN                 # YES
        cmp.l           %d1,&0x3fff8841         # IS X > 17/16?
        ble.w           LOGNEAR1                # NO

LOGMAIN:
#--THIS SHOULD BE THE USUAL CASE, X NOT VERY CLOSE TO 1

#--X = 2^(K) * Y, 1 <= Y < 2. THUS, Y = 1.XXXXXXXX....XX IN BINARY.
#--WE DEFINE F = 1.XXXXXX1, I.E. FIRST 7 BITS OF Y AND ATTACH A 1.
#--THE IDEA IS THAT LOG(X) = K*LOG2 + LOG(Y)
#--                      = K*LOG2 + LOG(F) + LOG(1 + (Y-F)/F).
#--NOTE THAT U = (Y-F)/F IS VERY SMALL AND THUS APPROXIMATING
#--LOG(1+U) CAN BE VERY EFFICIENT.
#--ALSO NOTE THAT THE VALUE 1/F IS STORED IN A TABLE SO THAT NO
#--DIVISION IS NEEDED TO CALCULATE (Y-F)/F.

#--GET K, Y, F, AND ADDRESS OF 1/F.
        asr.l           &8,%d1
        asr.l           &8,%d1                  # SHIFTED 16 BITS, BIASED EXPO. OF X
        sub.l           &0x3FFF,%d1             # THIS IS K
        add.l           ADJK(%a6),%d1           # ADJUST K, ORIGINAL INPUT MAY BE  DENORM.
        lea             LOGTBL(%pc),%a0         # BASE ADDRESS OF 1/F AND LOG(F)
        fmov.l          %d1,%fp1                # CONVERT K TO FLOATING-POINT FORMAT

#--WHILE THE CONVERSION IS GOING ON, WE GET F AND ADDRESS OF 1/F
        mov.l           &0x3FFF0000,X(%a6)      # X IS NOW Y, I.E. 2^(-K)*X
        mov.l           XFRAC(%a6),FFRAC(%a6)
        and.l           &0xFE000000,FFRAC(%a6)  # FIRST 7 BITS OF Y
        or.l            &0x01000000,FFRAC(%a6)  # GET F: ATTACH A 1 AT THE EIGHTH BIT
        mov.l           FFRAC(%a6),%d1  # READY TO GET ADDRESS OF 1/F
        and.l           &0x7E000000,%d1
        asr.l           &8,%d1
        asr.l           &8,%d1
        asr.l           &4,%d1                  # SHIFTED 20, D0 IS THE DISPLACEMENT
        add.l           %d1,%a0                 # A0 IS THE ADDRESS FOR 1/F

        fmov.x          X(%a6),%fp0
        mov.l           &0x3fff0000,F(%a6)
        clr.l           F+8(%a6)
        fsub.x          F(%a6),%fp0             # Y-F
        fmovm.x         &0xc,-(%sp)             # SAVE FP2-3 WHILE FP0 IS NOT READY
#--SUMMARY: FP0 IS Y-F, A0 IS ADDRESS OF 1/F, FP1 IS K
#--REGISTERS SAVED: FPCR, FP1, FP2

LP1CONT1:
#--AN RE-ENTRY POINT FOR LOGNP1
        fmul.x          (%a0),%fp0              # FP0 IS U = (Y-F)/F
        fmul.x          LOGOF2(%pc),%fp1        # GET K*LOG2 WHILE FP0 IS NOT READY
        fmov.x          %fp0,%fp2
        fmul.x          %fp2,%fp2               # FP2 IS V=U*U
        fmov.x          %fp1,KLOG2(%a6)         # PUT K*LOG2 IN MEMEORY, FREE FP1

#--LOG(1+U) IS APPROXIMATED BY
#--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS
#--[U + V*(A1+V*(A3+V*A5))]  +  [U*V*(A2+V*(A4+V*A6))]

        fmov.x          %fp2,%fp3
        fmov.x          %fp2,%fp1

        fmul.d          LOGA6(%pc),%fp1         # V*A6
        fmul.d          LOGA5(%pc),%fp2         # V*A5

        fadd.d          LOGA4(%pc),%fp1         # A4+V*A6
        fadd.d          LOGA3(%pc),%fp2         # A3+V*A5

        fmul.x          %fp3,%fp1               # V*(A4+V*A6)
        fmul.x          %fp3,%fp2               # V*(A3+V*A5)

        fadd.d          LOGA2(%pc),%fp1         # A2+V*(A4+V*A6)
        fadd.d          LOGA1(%pc),%fp2         # A1+V*(A3+V*A5)

        fmul.x          %fp3,%fp1               # V*(A2+V*(A4+V*A6))
        add.l           &16,%a0                 # ADDRESS OF LOG(F)
        fmul.x          %fp3,%fp2               # V*(A1+V*(A3+V*A5))

        fmul.x          %fp0,%fp1               # U*V*(A2+V*(A4+V*A6))
        fadd.x          %fp2,%fp0               # U+V*(A1+V*(A3+V*A5))

        fadd.x          (%a0),%fp1              # LOG(F)+U*V*(A2+V*(A4+V*A6))
        fmovm.x         (%sp)+,&0x30            # RESTORE FP2-3
        fadd.x          %fp1,%fp0               # FP0 IS LOG(F) + LOG(1+U)

        fmov.l          %d0,%fpcr
        fadd.x          KLOG2(%a6),%fp0         # FINAL ADD
        bra             t_inx2


LOGNEAR1:

# if the input is exactly equal to one, then exit through ld_pzero.
# if these 2 lines weren't here, the correct answer would be returned
# but the INEX2 bit would be set.
        fcmp.b          %fp0,&0x1               # is it equal to one?
        fbeq.l          ld_pzero                # yes

#--REGISTERS SAVED: FPCR, FP1. FP0 CONTAINS THE INPUT.
        fmov.x          %fp0,%fp1
        fsub.s          one(%pc),%fp1           # FP1 IS X-1
        fadd.s          one(%pc),%fp0           # FP0 IS X+1
        fadd.x          %fp1,%fp1               # FP1 IS 2(X-1)
#--LOG(X) = LOG(1+U/2)-LOG(1-U/2) WHICH IS AN ODD POLYNOMIAL
#--IN U, U = 2(X-1)/(X+1) = FP1/FP0

LP1CONT2:
#--THIS IS AN RE-ENTRY POINT FOR LOGNP1
        fdiv.x          %fp0,%fp1               # FP1 IS U
        fmovm.x         &0xc,-(%sp)             # SAVE FP2-3
#--REGISTERS SAVED ARE NOW FPCR,FP1,FP2,FP3
#--LET V=U*U, W=V*V, CALCULATE
#--U + U*V*(B1 + V*(B2 + V*(B3 + V*(B4 + V*B5)))) BY
#--U + U*V*(  [B1 + W*(B3 + W*B5)]  +  [V*(B2 + W*B4)]  )
        fmov.x          %fp1,%fp0
        fmul.x          %fp0,%fp0               # FP0 IS V
        fmov.x          %fp1,SAVEU(%a6)         # STORE U IN MEMORY, FREE FP1
        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # FP1 IS W

        fmov.d          LOGB5(%pc),%fp3
        fmov.d          LOGB4(%pc),%fp2

        fmul.x          %fp1,%fp3               # W*B5
        fmul.x          %fp1,%fp2               # W*B4

        fadd.d          LOGB3(%pc),%fp3         # B3+W*B5
        fadd.d          LOGB2(%pc),%fp2         # B2+W*B4

        fmul.x          %fp3,%fp1               # W*(B3+W*B5), FP3 RELEASED

        fmul.x          %fp0,%fp2               # V*(B2+W*B4)

        fadd.d          LOGB1(%pc),%fp1         # B1+W*(B3+W*B5)
        fmul.x          SAVEU(%a6),%fp0         # FP0 IS U*V

        fadd.x          %fp2,%fp1               # B1+W*(B3+W*B5) + V*(B2+W*B4), FP2 RELEASED
        fmovm.x         (%sp)+,&0x30            # FP2-3 RESTORED

        fmul.x          %fp1,%fp0               # U*V*( [B1+W*(B3+W*B5)] + [V*(B2+W*B4)] )

        fmov.l          %d0,%fpcr
        fadd.x          SAVEU(%a6),%fp0
        bra             t_inx2

#--REGISTERS SAVED FPCR. LOG(-VE) IS INVALID
LOGNEG:
        bra             t_operr

        global          slognd
slognd:
#--ENTRY POINT FOR LOG(X) FOR DENORMALIZED INPUT

        mov.l           &-100,ADJK(%a6)         # INPUT = 2^(ADJK) * FP0

#----normalize the input value by left shifting k bits (k to be determined
#----below), adjusting exponent and storing -k to  ADJK
#----the value TWOTO100 is no longer needed.
#----Note that this code assumes the denormalized input is NON-ZERO.

        movm.l          &0x3f00,-(%sp)          # save some registers  {d2-d7}
        mov.l           (%a0),%d3               # D3 is exponent of smallest norm. #
        mov.l           4(%a0),%d4
        mov.l           8(%a0),%d5              # (D4,D5) is (Hi_X,Lo_X)
        clr.l           %d2                     # D2 used for holding K

        tst.l           %d4
        bne.b           Hi_not0

Hi_0:
        mov.l           %d5,%d4
        clr.l           %d5
        mov.l           &32,%d2
        clr.l           %d6
        bfffo           %d4{&0:&32},%d6
        lsl.l           %d6,%d4
        add.l           %d6,%d2                 # (D3,D4,D5) is normalized

        mov.l           %d3,X(%a6)
        mov.l           %d4,XFRAC(%a6)
        mov.l           %d5,XFRAC+4(%a6)
        neg.l           %d2
        mov.l           %d2,ADJK(%a6)
        fmov.x          X(%a6),%fp0
        movm.l          (%sp)+,&0xfc            # restore registers {d2-d7}
        lea             X(%a6),%a0
        bra.w           LOGBGN                  # begin regular log(X)

Hi_not0:
        clr.l           %d6
        bfffo           %d4{&0:&32},%d6         # find first 1
        mov.l           %d6,%d2                 # get k
        lsl.l           %d6,%d4
        mov.l           %d5,%d7                 # a copy of D5
        lsl.l           %d6,%d5
        neg.l           %d6
        add.l           &32,%d6
        lsr.l           %d6,%d7
        or.l            %d7,%d4                 # (D3,D4,D5) normalized

        mov.l           %d3,X(%a6)
        mov.l           %d4,XFRAC(%a6)
        mov.l           %d5,XFRAC+4(%a6)
        neg.l           %d2
        mov.l           %d2,ADJK(%a6)
        fmov.x          X(%a6),%fp0
        movm.l          (%sp)+,&0xfc            # restore registers {d2-d7}
        lea             X(%a6),%a0
        bra.w           LOGBGN                  # begin regular log(X)

        global          slognp1
#--ENTRY POINT FOR LOG(1+X) FOR X FINITE, NON-ZERO, NOT NAN'S
slognp1:
        fmov.x          (%a0),%fp0              # LOAD INPUT
        fabs.x          %fp0                    # test magnitude
        fcmp.x          %fp0,LTHOLD(%pc)        # compare with min threshold
        fbgt.w          LP1REAL                 # if greater, continue
        fmov.l          %d0,%fpcr
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          (%a0),%fp0              # return signed argument
        bra             t_catch

LP1REAL:
        fmov.x          (%a0),%fp0              # LOAD INPUT
        mov.l           &0x00000000,ADJK(%a6)
        fmov.x          %fp0,%fp1               # FP1 IS INPUT Z
        fadd.s          one(%pc),%fp0           # X := ROUND(1+Z)
        fmov.x          %fp0,X(%a6)
        mov.w           XFRAC(%a6),XDCARE(%a6)
        mov.l           X(%a6),%d1
        cmp.l           %d1,&0
        ble.w           LP1NEG0                 # LOG OF ZERO OR -VE
        cmp.l           %d1,&0x3ffe8000         # IS BOUNDS [1/2,3/2]?
        blt.w           LOGMAIN
        cmp.l           %d1,&0x3fffc000
        bgt.w           LOGMAIN
#--IF 1+Z > 3/2 OR 1+Z < 1/2, THEN X, WHICH IS ROUNDING 1+Z,
#--CONTAINS AT LEAST 63 BITS OF INFORMATION OF Z. IN THAT CASE,
#--SIMPLY INVOKE LOG(X) FOR LOG(1+Z).

LP1NEAR1:
#--NEXT SEE IF EXP(-1/16) < X < EXP(1/16)
        cmp.l           %d1,&0x3ffef07d
        blt.w           LP1CARE
        cmp.l           %d1,&0x3fff8841
        bgt.w           LP1CARE

LP1ONE16:
#--EXP(-1/16) < X < EXP(1/16). LOG(1+Z) = LOG(1+U/2) - LOG(1-U/2)
#--WHERE U = 2Z/(2+Z) = 2Z/(1+X).
        fadd.x          %fp1,%fp1               # FP1 IS 2Z
        fadd.s          one(%pc),%fp0           # FP0 IS 1+X
#--U = FP1/FP0
        bra.w           LP1CONT2

LP1CARE:
#--HERE WE USE THE USUAL TABLE DRIVEN APPROACH. CARE HAS TO BE
#--TAKEN BECAUSE 1+Z CAN HAVE 67 BITS OF INFORMATION AND WE MUST
#--PRESERVE ALL THE INFORMATION. BECAUSE 1+Z IS IN [1/2,3/2],
#--THERE ARE ONLY TWO CASES.
#--CASE 1: 1+Z < 1, THEN K = -1 AND Y-F = (2-F) + 2Z
#--CASE 2: 1+Z > 1, THEN K = 0  AND Y-F = (1-F) + Z
#--ON RETURNING TO LP1CONT1, WE MUST HAVE K IN FP1, ADDRESS OF
#--(1/F) IN A0, Y-F IN FP0, AND FP2 SAVED.

        mov.l           XFRAC(%a6),FFRAC(%a6)
        and.l           &0xFE000000,FFRAC(%a6)
        or.l            &0x01000000,FFRAC(%a6)  # F OBTAINED
        cmp.l           %d1,&0x3FFF8000         # SEE IF 1+Z > 1
        bge.b           KISZERO

KISNEG1:
        fmov.s          TWO(%pc),%fp0
        mov.l           &0x3fff0000,F(%a6)
        clr.l           F+8(%a6)
        fsub.x          F(%a6),%fp0             # 2-F
        mov.l           FFRAC(%a6),%d1
        and.l           &0x7E000000,%d1
        asr.l           &8,%d1
        asr.l           &8,%d1
        asr.l           &4,%d1                  # D0 CONTAINS DISPLACEMENT FOR 1/F
        fadd.x          %fp1,%fp1               # GET 2Z
        fmovm.x         &0xc,-(%sp)             # SAVE FP2  {%fp2/%fp3}
        fadd.x          %fp1,%fp0               # FP0 IS Y-F = (2-F)+2Z
        lea             LOGTBL(%pc),%a0         # A0 IS ADDRESS OF 1/F
        add.l           %d1,%a0
        fmov.s          negone(%pc),%fp1        # FP1 IS K = -1
        bra.w           LP1CONT1

KISZERO:
        fmov.s          one(%pc),%fp0
        mov.l           &0x3fff0000,F(%a6)
        clr.l           F+8(%a6)
        fsub.x          F(%a6),%fp0             # 1-F
        mov.l           FFRAC(%a6),%d1
        and.l           &0x7E000000,%d1
        asr.l           &8,%d1
        asr.l           &8,%d1
        asr.l           &4,%d1
        fadd.x          %fp1,%fp0               # FP0 IS Y-F
        fmovm.x         &0xc,-(%sp)             # FP2 SAVED {%fp2/%fp3}
        lea             LOGTBL(%pc),%a0
        add.l           %d1,%a0                 # A0 IS ADDRESS OF 1/F
        fmov.s          zero(%pc),%fp1          # FP1 IS K = 0
        bra.w           LP1CONT1

LP1NEG0:
#--FPCR SAVED. D0 IS X IN COMPACT FORM.
        cmp.l           %d1,&0
        blt.b           LP1NEG
LP1ZERO:
        fmov.s          negone(%pc),%fp0

        fmov.l          %d0,%fpcr
        bra             t_dz

LP1NEG:
        fmov.s          zero(%pc),%fp0

        fmov.l          %d0,%fpcr
        bra             t_operr

        global          slognp1d
#--ENTRY POINT FOR LOG(1+Z) FOR DENORMALIZED INPUT
# Simply return the denorm
slognp1d:
        bra             t_extdnrm

#########################################################################
# satanh():  computes the inverse hyperbolic tangent of a norm input    #
# satanhd(): computes the inverse hyperbolic tangent of a denorm input  #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = arctanh(X)                                                #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 3 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       ATANH                                                           #
#       1. If |X| >= 1, go to 3.                                        #
#                                                                       #
#       2. (|X| < 1) Calculate atanh(X) by                              #
#               sgn := sign(X)                                          #
#               y := |X|                                                #
#               z := 2y/(1-y)                                           #
#               atanh(X) := sgn * (1/2) * logp1(z)                      #
#               Exit.                                                   #
#                                                                       #
#       3. If |X| > 1, go to 5.                                         #
#                                                                       #
#       4. (|X| = 1) Generate infinity with an appropriate sign and     #
#               divide-by-zero by                                       #
#               sgn := sign(X)                                          #
#               atan(X) := sgn / (+0).                                  #
#               Exit.                                                   #
#                                                                       #
#       5. (|X| > 1) Generate an invalid operation by 0 * infinity.     #
#               Exit.                                                   #
#                                                                       #
#########################################################################

        global          satanh
satanh:
        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1
        cmp.l           %d1,&0x3FFF8000
        bge.b           ATANHBIG

#--THIS IS THE USUAL CASE, |X| < 1
#--Y = |X|, Z = 2Y/(1-Y), ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z).

        fabs.x          (%a0),%fp0              # Y = |X|
        fmov.x          %fp0,%fp1
        fneg.x          %fp1                    # -Y
        fadd.x          %fp0,%fp0               # 2Y
        fadd.s          &0x3F800000,%fp1        # 1-Y
        fdiv.x          %fp1,%fp0               # 2Y/(1-Y)
        mov.l           (%a0),%d1
        and.l           &0x80000000,%d1
        or.l            &0x3F000000,%d1         # SIGN(X)*HALF
        mov.l           %d1,-(%sp)

        mov.l           %d0,-(%sp)              # save rnd prec,mode
        clr.l           %d0                     # pass ext prec,RN
        fmovm.x         &0x01,-(%sp)            # save Z on stack
        lea             (%sp),%a0               # pass ptr to Z
        bsr             slognp1                 # LOG1P(Z)
        add.l           &0xc,%sp                # clear Z from stack

        mov.l           (%sp)+,%d0              # fetch old prec,mode
        fmov.l          %d0,%fpcr               # load it
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.s          (%sp)+,%fp0
        bra             t_catch

ATANHBIG:
        fabs.x          (%a0),%fp0              # |X|
        fcmp.s          %fp0,&0x3F800000
        fbgt            t_operr
        bra             t_dz

        global          satanhd
#--ATANH(X) = X FOR DENORMALIZED X
satanhd:
        bra             t_extdnrm

#########################################################################
# slog10():  computes the base-10 logarithm of a normalized input       #
# slog10d(): computes the base-10 logarithm of a denormalized input     #
# slog2():   computes the base-2 logarithm of a normalized input        #
# slog2d():  computes the base-2 logarithm of a denormalized input      #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = log_10(X) or log_2(X)                                     #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 1.7 ulps in 64 significant bit,   #
#       i.e. within 0.5003 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       slog10d:                                                        #
#                                                                       #
#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
#       Notes:  Default means round-to-nearest mode, no floating-point  #
#               traps, and precision control = double extended.         #
#                                                                       #
#       Step 1. Call slognd to obtain Y = log(X), the natural log of X. #
#       Notes:  Even if X is denormalized, log(X) is always normalized. #
#                                                                       #
#       Step 2.  Compute log_10(X) = log(X) * (1/log(10)).              #
#            2.1 Restore the user FPCR                                  #
#            2.2 Return ans := Y * INV_L10.                             #
#                                                                       #
#       slog10:                                                         #
#                                                                       #
#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
#       Notes:  Default means round-to-nearest mode, no floating-point  #
#               traps, and precision control = double extended.         #
#                                                                       #
#       Step 1. Call sLogN to obtain Y = log(X), the natural log of X.  #
#                                                                       #
#       Step 2.   Compute log_10(X) = log(X) * (1/log(10)).             #
#            2.1  Restore the user FPCR                                 #
#            2.2  Return ans := Y * INV_L10.                            #
#                                                                       #
#       sLog2d:                                                         #
#                                                                       #
#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
#       Notes:  Default means round-to-nearest mode, no floating-point  #
#               traps, and precision control = double extended.         #
#                                                                       #
#       Step 1. Call slognd to obtain Y = log(X), the natural log of X. #
#       Notes:  Even if X is denormalized, log(X) is always normalized. #
#                                                                       #
#       Step 2.   Compute log_10(X) = log(X) * (1/log(2)).              #
#            2.1  Restore the user FPCR                                 #
#            2.2  Return ans := Y * INV_L2.                             #
#                                                                       #
#       sLog2:                                                          #
#                                                                       #
#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
#       Notes:  Default means round-to-nearest mode, no floating-point  #
#               traps, and precision control = double extended.         #
#                                                                       #
#       Step 1. If X is not an integer power of two, i.e., X != 2^k,    #
#               go to Step 3.                                           #
#                                                                       #
#       Step 2.   Return k.                                             #
#            2.1  Get integer k, X = 2^k.                               #
#            2.2  Restore the user FPCR.                                #
#            2.3  Return ans := convert-to-double-extended(k).          #
#                                                                       #
#       Step 3. Call sLogN to obtain Y = log(X), the natural log of X.  #
#                                                                       #
#       Step 4.   Compute log_2(X) = log(X) * (1/log(2)).               #
#            4.1  Restore the user FPCR                                 #
#            4.2  Return ans := Y * INV_L2.                             #
#                                                                       #
#########################################################################

INV_L10:
        long            0x3FFD0000,0xDE5BD8A9,0x37287195,0x00000000

INV_L2:
        long            0x3FFF0000,0xB8AA3B29,0x5C17F0BC,0x00000000

        global          slog10
#--entry point for Log10(X), X is normalized
slog10:
        fmov.b          &0x1,%fp0
        fcmp.x          %fp0,(%a0)              # if operand == 1,
        fbeq.l          ld_pzero                # return an EXACT zero

        mov.l           (%a0),%d1
        blt.w           invalid
        mov.l           %d0,-(%sp)
        clr.l           %d0
        bsr             slogn                   # log(X), X normal.
        fmov.l          (%sp)+,%fpcr
        fmul.x          INV_L10(%pc),%fp0
        bra             t_inx2

        global          slog10d
#--entry point for Log10(X), X is denormalized
slog10d:
        mov.l           (%a0),%d1
        blt.w           invalid
        mov.l           %d0,-(%sp)
        clr.l           %d0
        bsr             slognd                  # log(X), X denorm.
        fmov.l          (%sp)+,%fpcr
        fmul.x          INV_L10(%pc),%fp0
        bra             t_minx2

        global          slog2
#--entry point for Log2(X), X is normalized
slog2:
        mov.l           (%a0),%d1
        blt.w           invalid

        mov.l           8(%a0),%d1
        bne.b           continue                # X is not 2^k

        mov.l           4(%a0),%d1
        and.l           &0x7FFFFFFF,%d1
        bne.b           continue

#--X = 2^k.
        mov.w           (%a0),%d1
        and.l           &0x00007FFF,%d1
        sub.l           &0x3FFF,%d1
        beq.l           ld_pzero
        fmov.l          %d0,%fpcr
        fmov.l          %d1,%fp0
        bra             t_inx2

continue:
        mov.l           %d0,-(%sp)
        clr.l           %d0
        bsr             slogn                   # log(X), X normal.
        fmov.l          (%sp)+,%fpcr
        fmul.x          INV_L2(%pc),%fp0
        bra             t_inx2

invalid:
        bra             t_operr

        global          slog2d
#--entry point for Log2(X), X is denormalized
slog2d:
        mov.l           (%a0),%d1
        blt.w           invalid
        mov.l           %d0,-(%sp)
        clr.l           %d0
        bsr             slognd                  # log(X), X denorm.
        fmov.l          (%sp)+,%fpcr
        fmul.x          INV_L2(%pc),%fp0
        bra             t_minx2

#########################################################################
# stwotox():  computes 2**X for a normalized input                      #
# stwotoxd(): computes 2**X for a denormalized input                    #
# stentox():  computes 10**X for a normalized input                     #
# stentoxd(): computes 10**X for a denormalized input                   #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input                        #
#       d0 = round precision,mode                                       #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = 2**X or 10**X                                             #
#                                                                       #
# ACCURACY and MONOTONICITY ******************************************* #
#       The returned result is within 2 ulps in 64 significant bit,     #
#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
#       rounded to double precision. The result is provably monotonic   #
#       in double precision.                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       twotox                                                          #
#       1. If |X| > 16480, go to ExpBig.                                #
#                                                                       #
#       2. If |X| < 2**(-70), go to ExpSm.                              #
#                                                                       #
#       3. Decompose X as X = N/64 + r where |r| <= 1/128. Furthermore  #
#               decompose N as                                          #
#                N = 64(M + M') + j,  j = 0,1,2,...,63.                 #
#                                                                       #
#       4. Overwrite r := r * log2. Then                                #
#               2**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r).           #
#               Go to expr to compute that expression.                  #
#                                                                       #
#       tentox                                                          #
#       1. If |X| > 16480*log_10(2) (base 10 log of 2), go to ExpBig.   #
#                                                                       #
#       2. If |X| < 2**(-70), go to ExpSm.                              #
#                                                                       #
#       3. Set y := X*log_2(10)*64 (base 2 log of 10). Set              #
#               N := round-to-int(y). Decompose N as                    #
#                N = 64(M + M') + j,  j = 0,1,2,...,63.                 #
#                                                                       #
#       4. Define r as                                                  #
#               r := ((X - N*L1)-N*L2) * L10                            #
#               where L1, L2 are the leading and trailing parts of      #
#               log_10(2)/64 and L10 is the natural log of 10. Then     #
#               10**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r).          #
#               Go to expr to compute that expression.                  #
#                                                                       #
#       expr                                                            #
#       1. Fetch 2**(j/64) from table as Fact1 and Fact2.               #
#                                                                       #
#       2. Overwrite Fact1 and Fact2 by                                 #
#               Fact1 := 2**(M) * Fact1                                 #
#               Fact2 := 2**(M) * Fact2                                 #
#               Thus Fact1 + Fact2 = 2**(M) * 2**(j/64).                #
#                                                                       #
#       3. Calculate P where 1 + P approximates exp(r):                 #
#               P = r + r*r*(A1+r*(A2+...+r*A5)).                       #
#                                                                       #
#       4. Let AdjFact := 2**(M'). Return                               #
#               AdjFact * ( Fact1 + ((Fact1*P) + Fact2) ).              #
#               Exit.                                                   #
#                                                                       #
#       ExpBig                                                          #
#       1. Generate overflow by Huge * Huge if X > 0; otherwise,        #
#               generate underflow by Tiny * Tiny.                      #
#                                                                       #
#       ExpSm                                                           #
#       1. Return 1 + X.                                                #
#                                                                       #
#########################################################################

L2TEN64:
        long            0x406A934F,0x0979A371   # 64LOG10/LOG2
L10TWO1:
        long            0x3F734413,0x509F8000   # LOG2/64LOG10

L10TWO2:
        long            0xBFCD0000,0xC0219DC1,0xDA994FD2,0x00000000

LOG10:  long            0x40000000,0x935D8DDD,0xAAA8AC17,0x00000000

LOG2:   long            0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000

EXPA5:  long            0x3F56C16D,0x6F7BD0B2
EXPA4:  long            0x3F811112,0x302C712C
EXPA3:  long            0x3FA55555,0x55554CC1
EXPA2:  long            0x3FC55555,0x55554A54
EXPA1:  long            0x3FE00000,0x00000000,0x00000000,0x00000000

TEXPTBL:
        long            0x3FFF0000,0x80000000,0x00000000,0x3F738000
        long            0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBEF7CA
        long            0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBDF8A9
        long            0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBCD7C9
        long            0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBDE8DA
        long            0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBDE85C
        long            0x3FFF0000,0x88980E80,0x92DA8527,0x3FBEBBF1
        long            0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB80CA
        long            0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA8373
        long            0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE9670
        long            0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBDB700
        long            0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBEEEB0
        long            0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBBFD6D
        long            0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBDB319
        long            0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBDBA2B
        long            0x3FFF0000,0x96942D37,0x20185A00,0x3FBE91D5
        long            0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE8D5A
        long            0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBCDE7B
        long            0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBEBAAF
        long            0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD86DA
        long            0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBEBEDD
        long            0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBCC96E
        long            0x3FFF0000,0xA2704303,0x0C496819,0xBFBEC90B
        long            0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBBD1DB
        long            0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBCE5EB
        long            0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBEC274
        long            0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBEA83C
        long            0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBECB00
        long            0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE9301
        long            0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD8367
        long            0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBEF05F
        long            0x3FFF0000,0xB311C412,0xA9112489,0x3FBDFB3C
        long            0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBEB2FB
        long            0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBAE2CB
        long            0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBCDC3C
        long            0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBEE9AA
        long            0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBEAEFD
        long            0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBCBF51
        long            0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBEF88A
        long            0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD83B2
        long            0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBDF8AB
        long            0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBDFB17
        long            0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBEFE3C
        long            0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBBB6F8
        long            0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBCEE53
        long            0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBDA4AE
        long            0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC9124
        long            0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBEB243
        long            0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBDE69A
        long            0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB8BC61
        long            0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBDF610
        long            0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD8BE1
        long            0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBACB12
        long            0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB9BFE
        long            0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBCF2F4
        long            0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBEF22F
        long            0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBDBF4A
        long            0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBEC01A
        long            0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE8CAC
        long            0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBCBB3F
        long            0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBEF73A
        long            0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB8B795
        long            0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBEF84B
        long            0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBEF581

        set             INT,L_SCR1

        set             X,FP_SCR0
        set             XDCARE,X+2
        set             XFRAC,X+4

        set             ADJFACT,FP_SCR0

        set             FACT1,FP_SCR0
        set             FACT1HI,FACT1+4
        set             FACT1LOW,FACT1+8

        set             FACT2,FP_SCR1
        set             FACT2HI,FACT2+4
        set             FACT2LOW,FACT2+8

        global          stwotox
#--ENTRY POINT FOR 2**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
stwotox:
        fmovm.x         (%a0),&0x80             # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        fmov.x          %fp0,X(%a6)
        and.l           &0x7FFFFFFF,%d1

        cmp.l           %d1,&0x3FB98000         # |X| >= 2**(-70)?
        bge.b           TWOOK1
        bra.w           EXPBORS

TWOOK1:
        cmp.l           %d1,&0x400D80C0         # |X| > 16480?
        ble.b           TWOMAIN
        bra.w           EXPBORS

TWOMAIN:
#--USUAL CASE, 2^(-70) <= |X| <= 16480

        fmov.x          %fp0,%fp1
        fmul.s          &0x42800000,%fp1        # 64 * X
        fmov.l          %fp1,INT(%a6)           # N = ROUND-TO-INT(64 X)
        mov.l           %d2,-(%sp)
        lea             TEXPTBL(%pc),%a1        # LOAD ADDRESS OF TABLE OF 2^(J/64)
        fmov.l          INT(%a6),%fp1           # N --> FLOATING FMT
        mov.l           INT(%a6),%d1
        mov.l           %d1,%d2
        and.l           &0x3F,%d1               # D0 IS J
        asl.l           &4,%d1                  # DISPLACEMENT FOR 2^(J/64)
        add.l           %d1,%a1                 # ADDRESS FOR 2^(J/64)
        asr.l           &6,%d2                  # d2 IS L, N = 64L + J
        mov.l           %d2,%d1
        asr.l           &1,%d1                  # D0 IS M
        sub.l           %d1,%d2                 # d2 IS M', N = 64(M+M') + J
        add.l           &0x3FFF,%d2

#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64),
#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN.
#--ADJFACT = 2^(M').
#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2.

        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3

        fmul.s          &0x3C800000,%fp1        # (1/64)*N
        mov.l           (%a1)+,FACT1(%a6)
        mov.l           (%a1)+,FACT1HI(%a6)
        mov.l           (%a1)+,FACT1LOW(%a6)
        mov.w           (%a1)+,FACT2(%a6)

        fsub.x          %fp1,%fp0               # X - (1/64)*INT(64 X)

        mov.w           (%a1)+,FACT2HI(%a6)
        clr.w           FACT2HI+2(%a6)
        clr.l           FACT2LOW(%a6)
        add.w           %d1,FACT1(%a6)
        fmul.x          LOG2(%pc),%fp0          # FP0 IS R
        add.w           %d1,FACT2(%a6)

        bra.w           expr

EXPBORS:
#--FPCR, D0 SAVED
        cmp.l           %d1,&0x3FFF8000
        bgt.b           TEXPBIG

#--|X| IS SMALL, RETURN 1 + X

        fmov.l          %d0,%fpcr               # restore users round prec,mode
        fadd.s          &0x3F800000,%fp0        # RETURN 1 + X
        bra             t_pinx2

TEXPBIG:
#--|X| IS LARGE, GENERATE OVERFLOW IF X > 0; ELSE GENERATE UNDERFLOW
#--REGISTERS SAVE SO FAR ARE FPCR AND  D0
        mov.l           X(%a6),%d1
        cmp.l           %d1,&0
        blt.b           EXPNEG

        bra             t_ovfl2                 # t_ovfl expects positive value

EXPNEG:
        bra             t_unfl2                 # t_unfl expects positive value

        global          stwotoxd
stwotoxd:
#--ENTRY POINT FOR 2**(X) FOR DENORMALIZED ARGUMENT

        fmov.l          %d0,%fpcr               # set user's rounding mode/precision
        fmov.s          &0x3F800000,%fp0        # RETURN 1 + X
        mov.l           (%a0),%d1
        or.l            &0x00800001,%d1
        fadd.s          %d1,%fp0
        bra             t_pinx2

        global          stentox
#--ENTRY POINT FOR 10**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
stentox:
        fmovm.x         (%a0),&0x80             # LOAD INPUT

        mov.l           (%a0),%d1
        mov.w           4(%a0),%d1
        fmov.x          %fp0,X(%a6)
        and.l           &0x7FFFFFFF,%d1

        cmp.l           %d1,&0x3FB98000         # |X| >= 2**(-70)?
        bge.b           TENOK1
        bra.w           EXPBORS

TENOK1:
        cmp.l           %d1,&0x400B9B07         # |X| <= 16480*log2/log10 ?
        ble.b           TENMAIN
        bra.w           EXPBORS

TENMAIN:
#--USUAL CASE, 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10

        fmov.x          %fp0,%fp1
        fmul.d          L2TEN64(%pc),%fp1       # X*64*LOG10/LOG2
        fmov.l          %fp1,INT(%a6)           # N=INT(X*64*LOG10/LOG2)
        mov.l           %d2,-(%sp)
        lea             TEXPTBL(%pc),%a1        # LOAD ADDRESS OF TABLE OF 2^(J/64)
        fmov.l          INT(%a6),%fp1           # N --> FLOATING FMT
        mov.l           INT(%a6),%d1
        mov.l           %d1,%d2
        and.l           &0x3F,%d1               # D0 IS J
        asl.l           &4,%d1                  # DISPLACEMENT FOR 2^(J/64)
        add.l           %d1,%a1                 # ADDRESS FOR 2^(J/64)
        asr.l           &6,%d2                  # d2 IS L, N = 64L + J
        mov.l           %d2,%d1
        asr.l           &1,%d1                  # D0 IS M
        sub.l           %d1,%d2                 # d2 IS M', N = 64(M+M') + J
        add.l           &0x3FFF,%d2

#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64),
#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN.
#--ADJFACT = 2^(M').
#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2.
        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3

        fmov.x          %fp1,%fp2

        fmul.d          L10TWO1(%pc),%fp1       # N*(LOG2/64LOG10)_LEAD
        mov.l           (%a1)+,FACT1(%a6)

        fmul.x          L10TWO2(%pc),%fp2       # N*(LOG2/64LOG10)_TRAIL

        mov.l           (%a1)+,FACT1HI(%a6)
        mov.l           (%a1)+,FACT1LOW(%a6)
        fsub.x          %fp1,%fp0               # X - N L_LEAD
        mov.w           (%a1)+,FACT2(%a6)

        fsub.x          %fp2,%fp0               # X - N L_TRAIL

        mov.w           (%a1)+,FACT2HI(%a6)
        clr.w           FACT2HI+2(%a6)
        clr.l           FACT2LOW(%a6)

        fmul.x          LOG10(%pc),%fp0         # FP0 IS R
        add.w           %d1,FACT1(%a6)
        add.w           %d1,FACT2(%a6)

expr:
#--FPCR, FP2, FP3 ARE SAVED IN ORDER AS SHOWN.
#--ADJFACT CONTAINS 2**(M'), FACT1 + FACT2 = 2**(M) * 2**(J/64).
#--FP0 IS R. THE FOLLOWING CODE COMPUTES
#--     2**(M'+M) * 2**(J/64) * EXP(R)

        fmov.x          %fp0,%fp1
        fmul.x          %fp1,%fp1               # FP1 IS S = R*R

        fmov.d          EXPA5(%pc),%fp2         # FP2 IS A5
        fmov.d          EXPA4(%pc),%fp3         # FP3 IS A4

        fmul.x          %fp1,%fp2               # FP2 IS S*A5
        fmul.x          %fp1,%fp3               # FP3 IS S*A4

        fadd.d          EXPA3(%pc),%fp2         # FP2 IS A3+S*A5
        fadd.d          EXPA2(%pc),%fp3         # FP3 IS A2+S*A4

        fmul.x          %fp1,%fp2               # FP2 IS S*(A3+S*A5)
        fmul.x          %fp1,%fp3               # FP3 IS S*(A2+S*A4)

        fadd.d          EXPA1(%pc),%fp2         # FP2 IS A1+S*(A3+S*A5)
        fmul.x          %fp0,%fp3               # FP3 IS R*S*(A2+S*A4)

        fmul.x          %fp1,%fp2               # FP2 IS S*(A1+S*(A3+S*A5))
        fadd.x          %fp3,%fp0               # FP0 IS R+R*S*(A2+S*A4)
        fadd.x          %fp2,%fp0               # FP0 IS EXP(R) - 1

        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3

#--FINAL RECONSTRUCTION PROCESS
#--EXP(X) = 2^M*2^(J/64) + 2^M*2^(J/64)*(EXP(R)-1)  -  (1 OR 0)

        fmul.x          FACT1(%a6),%fp0
        fadd.x          FACT2(%a6),%fp0
        fadd.x          FACT1(%a6),%fp0

        fmov.l          %d0,%fpcr               # restore users round prec,mode
        mov.w           %d2,ADJFACT(%a6)        # INSERT EXPONENT
        mov.l           (%sp)+,%d2
        mov.l           &0x80000000,ADJFACT+4(%a6)
        clr.l           ADJFACT+8(%a6)
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.x          ADJFACT(%a6),%fp0       # FINAL ADJUSTMENT
        bra             t_catch

        global          stentoxd
stentoxd:
#--ENTRY POINT FOR 10**(X) FOR DENORMALIZED ARGUMENT

        fmov.l          %d0,%fpcr               # set user's rounding mode/precision
        fmov.s          &0x3F800000,%fp0        # RETURN 1 + X
        mov.l           (%a0),%d1
        or.l            &0x00800001,%d1
        fadd.s          %d1,%fp0
        bra             t_pinx2

#########################################################################
# sscale(): computes the destination operand scaled by the source       #
#           operand. If the absoulute value of the source operand is    #
#           >= 2^14, an overflow or underflow is returned.              #
#                                                                       #
# INPUT *************************************************************** #
#       a0  = pointer to double-extended source operand X               #
#       a1  = pointer to double-extended destination operand Y          #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 =  scale(X,Y)                                               #
#                                                                       #
#########################################################################

set     SIGN,           L_SCR1

        global          sscale
sscale:
        mov.l           %d0,-(%sp)              # store off ctrl bits for now

        mov.w           DST_EX(%a1),%d1         # get dst exponent
        smi.b           SIGN(%a6)               # use SIGN to hold dst sign
        andi.l          &0x00007fff,%d1         # strip sign from dst exp

        mov.w           SRC_EX(%a0),%d0         # check src bounds
        andi.w          &0x7fff,%d0             # clr src sign bit
        cmpi.w          %d0,&0x3fff             # is src ~ ZERO?
        blt.w           src_small               # yes
        cmpi.w          %d0,&0x400c             # no; is src too big?
        bgt.w           src_out                 # yes

#
# Source is within 2^14 range.
#
src_ok:
        fintrz.x        SRC(%a0),%fp0           # calc int of src
        fmov.l          %fp0,%d0                # int src to d0
# don't want any accrued bits from the fintrz showing up later since
# we may need to read the fpsr for the last fp op in t_catch2().
        fmov.l          &0x0,%fpsr

        tst.b           DST_HI(%a1)             # is dst denormalized?
        bmi.b           sok_norm

# the dst is a DENORM. normalize the DENORM and add the adjustment to
# the src value. then, jump to the norm part of the routine.
sok_dnrm:
        mov.l           %d0,-(%sp)              # save src for now

        mov.w           DST_EX(%a1),FP_SCR0_EX(%a6) # make a copy
        mov.l           DST_HI(%a1),FP_SCR0_HI(%a6)
        mov.l           DST_LO(%a1),FP_SCR0_LO(%a6)

        lea             FP_SCR0(%a6),%a0        # pass ptr to DENORM
        bsr.l           norm                    # normalize the DENORM
        neg.l           %d0
        add.l           (%sp)+,%d0              # add adjustment to src

        fmovm.x         FP_SCR0(%a6),&0x80      # load normalized DENORM

        cmpi.w          %d0,&-0x3fff            # is the shft amt really low?
        bge.b           sok_norm2               # thank goodness no

# the multiply factor that we're trying to create should be a denorm
# for the multiply to work. therefore, we're going to actually do a
# multiply with a denorm which will cause an unimplemented data type
# exception to be put into the machine which will be caught and corrected
# later. we don't do this with the DENORMs above because this method
# is slower. but, don't fret, I don't see it being used much either.
        fmov.l          (%sp)+,%fpcr            # restore user fpcr
        mov.l           &0x80000000,%d1         # load normalized mantissa
        subi.l          &-0x3fff,%d0            # how many should we shift?
        neg.l           %d0                     # make it positive
        cmpi.b          %d0,&0x20               # is it > 32?
        bge.b           sok_dnrm_32             # yes
        lsr.l           %d0,%d1                 # no; bit stays in upper lw
        clr.l           -(%sp)                  # insert zero low mantissa
        mov.l           %d1,-(%sp)              # insert new high mantissa
        clr.l           -(%sp)                  # make zero exponent
        bra.b           sok_norm_cont
sok_dnrm_32:
        subi.b          &0x20,%d0               # get shift count
        lsr.l           %d0,%d1                 # make low mantissa longword
        mov.l           %d1,-(%sp)              # insert new low mantissa
        clr.l           -(%sp)                  # insert zero high mantissa
        clr.l           -(%sp)                  # make zero exponent
        bra.b           sok_norm_cont

# the src will force the dst to a DENORM value or worse. so, let's
# create an fp multiply that will create the result.
sok_norm:
        fmovm.x         DST(%a1),&0x80          # load fp0 with normalized src
sok_norm2:
        fmov.l          (%sp)+,%fpcr            # restore user fpcr

        addi.w          &0x3fff,%d0             # turn src amt into exp value
        swap            %d0                     # put exponent in high word
        clr.l           -(%sp)                  # insert new exponent
        mov.l           &0x80000000,-(%sp)      # insert new high mantissa
        mov.l           %d0,-(%sp)              # insert new lo mantissa

sok_norm_cont:
        fmov.l          %fpcr,%d0               # d0 needs fpcr for t_catch2
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.x          (%sp)+,%fp0             # do the multiply
        bra             t_catch2                # catch any exceptions

#
# Source is outside of 2^14 range.  Test the sign and branch
# to the appropriate exception handler.
#
src_out:
        mov.l           (%sp)+,%d0              # restore ctrl bits
        exg             %a0,%a1                 # swap src,dst ptrs
        tst.b           SRC_EX(%a1)             # is src negative?
        bmi             t_unfl                  # yes; underflow
        bra             t_ovfl_sc               # no; overflow

#
# The source input is below 1, so we check for denormalized numbers
# and set unfl.
#
src_small:
        tst.b           DST_HI(%a1)             # is dst denormalized?
        bpl.b           ssmall_done             # yes

        mov.l           (%sp)+,%d0
        fmov.l          %d0,%fpcr               # no; load control bits
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          DST(%a1),%fp0           # simply return dest
        bra             t_catch2
ssmall_done:
        mov.l           (%sp)+,%d0              # load control bits into d1
        mov.l           %a1,%a0                 # pass ptr to dst
        bra             t_resdnrm

#########################################################################
# smod(): computes the fp MOD of the input values X,Y.                  #
# srem(): computes the fp (IEEE) REM of the input values X,Y.           #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input X                      #
#       a1 = pointer to extended precision input Y                      #
#       d0 = round precision,mode                                       #
#                                                                       #
#       The input operands X and Y can be either normalized or          #
#       denormalized.                                                   #
#                                                                       #
# OUTPUT ************************************************************** #
#      fp0 = FREM(X,Y) or FMOD(X,Y)                                     #
#                                                                       #
# ALGORITHM *********************************************************** #
#                                                                       #
#       Step 1.  Save and strip signs of X and Y: signX := sign(X),     #
#                signY := sign(Y), X := |X|, Y := |Y|,                  #
#                signQ := signX EOR signY. Record whether MOD or REM    #
#                is requested.                                          #
#                                                                       #
#       Step 2.  Set L := expo(X)-expo(Y), k := 0, Q := 0.              #
#                If (L < 0) then                                        #
#                   R := X, go to Step 4.                               #
#                else                                                   #
#                   R := 2^(-L)X, j := L.                               #
#                endif                                                  #
#                                                                       #
#       Step 3.  Perform MOD(X,Y)                                       #
#            3.1 If R = Y, go to Step 9.                                #
#            3.2 If R > Y, then { R := R - Y, Q := Q + 1}               #
#            3.3 If j = 0, go to Step 4.                                #
#            3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to        #
#                Step 3.1.                                              #
#                                                                       #
#       Step 4.  At this point, R = X - QY = MOD(X,Y). Set              #
#                Last_Subtract := false (used in Step 7 below). If      #
#                MOD is requested, go to Step 6.                        #
#                                                                       #
#       Step 5.  R = MOD(X,Y), but REM(X,Y) is requested.               #
#            5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to        #
#                Step 6.                                                #
#            5.2 If R > Y/2, then { set Last_Subtract := true,          #
#                Q := Q + 1, Y := signY*Y }. Go to Step 6.              #
#            5.3 This is the tricky case of R = Y/2. If Q is odd,       #
#                then { Q := Q + 1, signX := -signX }.                  #
#                                                                       #
#       Step 6.  R := signX*R.                                          #
#                                                                       #
#       Step 7.  If Last_Subtract = true, R := R - Y.                   #
#                                                                       #
#       Step 8.  Return signQ, last 7 bits of Q, and R as required.     #
#                                                                       #
#       Step 9.  At this point, R = 2^(-j)*X - Q Y = Y. Thus,           #
#                X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1),                #
#                R := 0. Return signQ, last 7 bits of Q, and R.         #
#                                                                       #
#########################################################################

        set             Mod_Flag,L_SCR3
        set             Sc_Flag,L_SCR3+1

        set             SignY,L_SCR2
        set             SignX,L_SCR2+2
        set             SignQ,L_SCR3+2

        set             Y,FP_SCR0
        set             Y_Hi,Y+4
        set             Y_Lo,Y+8

        set             R,FP_SCR1
        set             R_Hi,R+4
        set             R_Lo,R+8

Scale:
        long            0x00010000,0x80000000,0x00000000,0x00000000

        global          smod
smod:
        clr.b           FPSR_QBYTE(%a6)
        mov.l           %d0,-(%sp)              # save ctrl bits
        clr.b           Mod_Flag(%a6)
        bra.b           Mod_Rem

        global          srem
srem:
        clr.b           FPSR_QBYTE(%a6)
        mov.l           %d0,-(%sp)              # save ctrl bits
        mov.b           &0x1,Mod_Flag(%a6)

Mod_Rem:
#..Save sign of X and Y
        movm.l          &0x3f00,-(%sp)          # save data registers
        mov.w           SRC_EX(%a0),%d3
        mov.w           %d3,SignY(%a6)
        and.l           &0x00007FFF,%d3         # Y := |Y|

#
        mov.l           SRC_HI(%a0),%d4
        mov.l           SRC_LO(%a0),%d5         # (D3,D4,D5) is |Y|

        tst.l           %d3
        bne.b           Y_Normal

        mov.l           &0x00003FFE,%d3         # $3FFD + 1
        tst.l           %d4
        bne.b           HiY_not0

HiY_0:
        mov.l           %d5,%d4
        clr.l           %d5
        sub.l           &32,%d3
        clr.l           %d6
        bfffo           %d4{&0:&32},%d6
        lsl.l           %d6,%d4
        sub.l           %d6,%d3                 # (D3,D4,D5) is normalized
#                                               ...with bias $7FFD
        bra.b           Chk_X

HiY_not0:
        clr.l           %d6
        bfffo           %d4{&0:&32},%d6
        sub.l           %d6,%d3
        lsl.l           %d6,%d4
        mov.l           %d5,%d7                 # a copy of D5
        lsl.l           %d6,%d5
        neg.l           %d6
        add.l           &32,%d6
        lsr.l           %d6,%d7
        or.l            %d7,%d4                 # (D3,D4,D5) normalized
#                                       ...with bias $7FFD
        bra.b           Chk_X

Y_Normal:
        add.l           &0x00003FFE,%d3         # (D3,D4,D5) normalized
#                                       ...with bias $7FFD

Chk_X:
        mov.w           DST_EX(%a1),%d0
        mov.w           %d0,SignX(%a6)
        mov.w           SignY(%a6),%d1
        eor.l           %d0,%d1
        and.l           &0x00008000,%d1
        mov.w           %d1,SignQ(%a6)          # sign(Q) obtained
        and.l           &0x00007FFF,%d0
        mov.l           DST_HI(%a1),%d1
        mov.l           DST_LO(%a1),%d2         # (D0,D1,D2) is |X|
        tst.l           %d0
        bne.b           X_Normal
        mov.l           &0x00003FFE,%d0
        tst.l           %d1
        bne.b           HiX_not0

HiX_0:
        mov.l           %d2,%d1
        clr.l           %d2
        sub.l           &32,%d0
        clr.l           %d6
        bfffo           %d1{&0:&32},%d6
        lsl.l           %d6,%d1
        sub.l           %d6,%d0                 # (D0,D1,D2) is normalized
#                                       ...with bias $7FFD
        bra.b           Init

HiX_not0:
        clr.l           %d6
        bfffo           %d1{&0:&32},%d6
        sub.l           %d6,%d0
        lsl.l           %d6,%d1
        mov.l           %d2,%d7                 # a copy of D2
        lsl.l           %d6,%d2
        neg.l           %d6
        add.l           &32,%d6
        lsr.l           %d6,%d7
        or.l            %d7,%d1                 # (D0,D1,D2) normalized
#                                       ...with bias $7FFD
        bra.b           Init

X_Normal:
        add.l           &0x00003FFE,%d0         # (D0,D1,D2) normalized
#                                       ...with bias $7FFD

Init:
#
        mov.l           %d3,L_SCR1(%a6)         # save biased exp(Y)
        mov.l           %d0,-(%sp)              # save biased exp(X)
        sub.l           %d3,%d0                 # L := expo(X)-expo(Y)

        clr.l           %d6                     # D6 := carry <- 0
        clr.l           %d3                     # D3 is Q
        mov.l           &0,%a1                  # A1 is k; j+k=L, Q=0

#..(Carry,D1,D2) is R
        tst.l           %d0
        bge.b           Mod_Loop_pre

#..expo(X) < expo(Y). Thus X = mod(X,Y)
#
        mov.l           (%sp)+,%d0              # restore d0
        bra.w           Get_Mod

Mod_Loop_pre:
        addq.l          &0x4,%sp                # erase exp(X)
#..At this point  R = 2^(-L)X; Q = 0; k = 0; and  k+j = L
Mod_Loop:
        tst.l           %d6                     # test carry bit
        bgt.b           R_GT_Y

#..At this point carry = 0, R = (D1,D2), Y = (D4,D5)
        cmp.l           %d1,%d4                 # compare hi(R) and hi(Y)
        bne.b           R_NE_Y
        cmp.l           %d2,%d5                 # compare lo(R) and lo(Y)
        bne.b           R_NE_Y

#..At this point, R = Y
        bra.w           Rem_is_0

R_NE_Y:
#..use the borrow of the previous compare
        bcs.b           R_LT_Y                  # borrow is set iff R < Y

R_GT_Y:
#..If Carry is set, then Y < (Carry,D1,D2) < 2Y. Otherwise, Carry = 0
#..and Y < (D1,D2) < 2Y. Either way, perform R - Y
        sub.l           %d5,%d2                 # lo(R) - lo(Y)
        subx.l          %d4,%d1                 # hi(R) - hi(Y)
        clr.l           %d6                     # clear carry
        addq.l          &1,%d3                  # Q := Q + 1

R_LT_Y:
#..At this point, Carry=0, R < Y. R = 2^(k-L)X - QY; k+j = L; j >= 0.
        tst.l           %d0                     # see if j = 0.
        beq.b           PostLoop

        add.l           %d3,%d3                 # Q := 2Q
        add.l           %d2,%d2                 # lo(R) = 2lo(R)
        roxl.l          &1,%d1                  # hi(R) = 2hi(R) + carry
        scs             %d6                     # set Carry if 2(R) overflows
        addq.l          &1,%a1                  # k := k+1
        subq.l          &1,%d0                  # j := j - 1
#..At this point, R=(Carry,D1,D2) = 2^(k-L)X - QY, j+k=L, j >= 0, R < 2Y.

        bra.b           Mod_Loop

PostLoop:
#..k = L, j = 0, Carry = 0, R = (D1,D2) = X - QY, R < Y.

#..normalize R.
        mov.l           L_SCR1(%a6),%d0         # new biased expo of R
        tst.l           %d1
        bne.b           HiR_not0

HiR_0:
        mov.l           %d2,%d1
        clr.l           %d2
        sub.l           &32,%d0
        clr.l           %d6
        bfffo           %d1{&0:&32},%d6
        lsl.l           %d6,%d1
        sub.l           %d6,%d0                 # (D0,D1,D2) is normalized
#                                       ...with bias $7FFD
        bra.b           Get_Mod

HiR_not0:
        clr.l           %d6
        bfffo           %d1{&0:&32},%d6
        bmi.b           Get_Mod                 # already normalized
        sub.l           %d6,%d0
        lsl.l           %d6,%d1
        mov.l           %d2,%d7                 # a copy of D2
        lsl.l           %d6,%d2
        neg.l           %d6
        add.l           &32,%d6
        lsr.l           %d6,%d7
        or.l            %d7,%d1                 # (D0,D1,D2) normalized

#
Get_Mod:
        cmp.l           %d0,&0x000041FE
        bge.b           No_Scale
Do_Scale:
        mov.w           %d0,R(%a6)
        mov.l           %d1,R_Hi(%a6)
        mov.l           %d2,R_Lo(%a6)
        mov.l           L_SCR1(%a6),%d6
        mov.w           %d6,Y(%a6)
        mov.l           %d4,Y_Hi(%a6)
        mov.l           %d5,Y_Lo(%a6)
        fmov.x          R(%a6),%fp0             # no exception
        mov.b           &1,Sc_Flag(%a6)
        bra.b           ModOrRem
No_Scale:
        mov.l           %d1,R_Hi(%a6)
        mov.l           %d2,R_Lo(%a6)
        sub.l           &0x3FFE,%d0
        mov.w           %d0,R(%a6)
        mov.l           L_SCR1(%a6),%d6
        sub.l           &0x3FFE,%d6
        mov.l           %d6,L_SCR1(%a6)
        fmov.x          R(%a6),%fp0
        mov.w           %d6,Y(%a6)
        mov.l           %d4,Y_Hi(%a6)
        mov.l           %d5,Y_Lo(%a6)
        clr.b           Sc_Flag(%a6)

#
ModOrRem:
        tst.b           Mod_Flag(%a6)
        beq.b           Fix_Sign

        mov.l           L_SCR1(%a6),%d6         # new biased expo(Y)
        subq.l          &1,%d6                  # biased expo(Y/2)
        cmp.l           %d0,%d6
        blt.b           Fix_Sign
        bgt.b           Last_Sub

        cmp.l           %d1,%d4
        bne.b           Not_EQ
        cmp.l           %d2,%d5
        bne.b           Not_EQ
        bra.w           Tie_Case

Not_EQ:
        bcs.b           Fix_Sign

Last_Sub:
#
        fsub.x          Y(%a6),%fp0             # no exceptions
        addq.l          &1,%d3                  # Q := Q + 1

#
Fix_Sign:
#..Get sign of X
        mov.w           SignX(%a6),%d6
        bge.b           Get_Q
        fneg.x          %fp0

#..Get Q
#
Get_Q:
        clr.l           %d6
        mov.w           SignQ(%a6),%d6          # D6 is sign(Q)
        mov.l           &8,%d7
        lsr.l           %d7,%d6
        and.l           &0x0000007F,%d3         # 7 bits of Q
        or.l            %d6,%d3                 # sign and bits of Q
#       swap            %d3
#       fmov.l          %fpsr,%d6
#       and.l           &0xFF00FFFF,%d6
#       or.l            %d3,%d6
#       fmov.l          %d6,%fpsr               # put Q in fpsr
        mov.b           %d3,FPSR_QBYTE(%a6)     # put Q in fpsr

#
Restore:
        movm.l          (%sp)+,&0xfc            #  {%d2-%d7}
        mov.l           (%sp)+,%d0
        fmov.l          %d0,%fpcr
        tst.b           Sc_Flag(%a6)
        beq.b           Finish
        mov.b           &FMUL_OP,%d1            # last inst is MUL
        fmul.x          Scale(%pc),%fp0         # may cause underflow
        bra             t_catch2
# the '040 package did this apparently to see if the dst operand for the
# preceding fmul was a denorm. but, it better not have been since the
# algorithm just got done playing with fp0 and expected no exceptions
# as a result. trust me...
#       bra             t_avoid_unsupp          # check for denorm as a
#                                               ;result of the scaling

Finish:
        mov.b           &FMOV_OP,%d1            # last inst is MOVE
        fmov.x          %fp0,%fp0               # capture exceptions & round
        bra             t_catch2

Rem_is_0:
#..R = 2^(-j)X - Q Y = Y, thus R = 0 and quotient = 2^j (Q+1)
        addq.l          &1,%d3
        cmp.l           %d0,&8                  # D0 is j
        bge.b           Q_Big

        lsl.l           %d0,%d3
        bra.b           Set_R_0

Q_Big:
        clr.l           %d3

Set_R_0:
        fmov.s          &0x00000000,%fp0
        clr.b           Sc_Flag(%a6)
        bra.w           Fix_Sign

Tie_Case:
#..Check parity of Q
        mov.l           %d3,%d6
        and.l           &0x00000001,%d6
        tst.l           %d6
        beq.w           Fix_Sign                # Q is even

#..Q is odd, Q := Q + 1, signX := -signX
        addq.l          &1,%d3
        mov.w           SignX(%a6),%d6
        eor.l           &0x00008000,%d6
        mov.w           %d6,SignX(%a6)
        bra.w           Fix_Sign

#########################################################################
# XDEF **************************************************************** #
#       tag(): return the optype of the input ext fp number             #
#                                                                       #
#       This routine is used by the 060FPLSP.                           #
#                                                                       #
# XREF **************************************************************** #
#       None                                                            #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision operand                      #
#                                                                       #
# OUTPUT ************************************************************** #
#       d0 = value of type tag                                          #
#               one of: NORM, INF, QNAN, SNAN, DENORM, ZERO             #
#                                                                       #
# ALGORITHM *********************************************************** #
#       Simply test the exponent, j-bit, and mantissa values to         #
# determine the type of operand.                                        #
#       If it's an unnormalized zero, alter the operand and force it    #
# to be a normal zero.                                                  #
#                                                                       #
#########################################################################

        global          tag
tag:
        mov.w           FTEMP_EX(%a0), %d0      # extract exponent
        andi.w          &0x7fff, %d0            # strip off sign
        cmpi.w          %d0, &0x7fff            # is (EXP == MAX)?
        beq.b           inf_or_nan_x
not_inf_or_nan_x:
        btst            &0x7,FTEMP_HI(%a0)
        beq.b           not_norm_x
is_norm_x:
        mov.b           &NORM, %d0
        rts
not_norm_x:
        tst.w           %d0                     # is exponent = 0?
        bne.b           is_unnorm_x
not_unnorm_x:
        tst.l           FTEMP_HI(%a0)
        bne.b           is_denorm_x
        tst.l           FTEMP_LO(%a0)
        bne.b           is_denorm_x
is_zero_x:
        mov.b           &ZERO, %d0
        rts
is_denorm_x:
        mov.b           &DENORM, %d0
        rts
is_unnorm_x:
        bsr.l           unnorm_fix              # convert to norm,denorm,or zero
        rts
is_unnorm_reg_x:
        mov.b           &UNNORM, %d0
        rts
inf_or_nan_x:
        tst.l           FTEMP_LO(%a0)
        bne.b           is_nan_x
        mov.l           FTEMP_HI(%a0), %d0
        and.l           &0x7fffffff, %d0        # msb is a don't care!
        bne.b           is_nan_x
is_inf_x:
        mov.b           &INF, %d0
        rts
is_nan_x:
        mov.b           &QNAN, %d0
        rts

#############################################################

qnan:   long            0x7fff0000, 0xffffffff, 0xffffffff

#########################################################################
# XDEF **************************************************************** #
#       t_dz(): Handle 060FPLSP dz exception for "flogn" emulation.     #
#       t_dz2(): Handle 060FPLSP dz exception for "fatanh" emulation.   #
#                                                                       #
#       These rouitnes are used by the 060FPLSP package.                #
#                                                                       #
# XREF **************************************************************** #
#       None                                                            #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision source operand.              #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default DZ result.                                        #
#                                                                       #
# ALGORITHM *********************************************************** #
#       Transcendental emulation for the 060FPLSP has detected that     #
# a DZ exception should occur for the instruction. If DZ is disabled,   #
# return the default result.                                            #
#       If DZ is enabled, the dst operand should be returned unscathed  #
# in fp0 while fp1 is used to create a DZ exception so that the         #
# operating system can log that such an event occurred.                 #
#                                                                       #
#########################################################################

        global          t_dz
t_dz:
        tst.b           SRC_EX(%a0)             # check sign for neg or pos
        bpl.b           dz_pinf                 # branch if pos sign

        global          t_dz2
t_dz2:
        ori.l           &dzinf_mask+neg_mask,USER_FPSR(%a6) # set N/I/DZ/ADZ

        btst            &dz_bit,FPCR_ENABLE(%a6)
        bne.b           dz_minf_ena

# dz is disabled. return a -INF.
        fmov.s          &0xff800000,%fp0        # return -INF
        rts

# dz is enabled. create a dz exception so the user can record it
# but use fp1 instead. return the dst operand unscathed in fp0.
dz_minf_ena:
        fmovm.x         EXC_FP0(%a6),&0x80      # return fp0 unscathed
        fmov.l          USER_FPCR(%a6),%fpcr
        fmov.s          &0xbf800000,%fp1        # load -1
        fdiv.s          &0x00000000,%fp1        # -1 / 0
        rts

dz_pinf:
        ori.l           &dzinf_mask,USER_FPSR(%a6) # set I/DZ/ADZ

        btst            &dz_bit,FPCR_ENABLE(%a6)
        bne.b           dz_pinf_ena

# dz is disabled. return a +INF.
        fmov.s          &0x7f800000,%fp0        # return +INF
        rts

# dz is enabled. create a dz exception so the user can record it
# but use fp1 instead. return the dst operand unscathed in fp0.
dz_pinf_ena:
        fmovm.x         EXC_FP0(%a6),&0x80      # return fp0 unscathed
        fmov.l          USER_FPCR(%a6),%fpcr
        fmov.s          &0x3f800000,%fp1        # load +1
        fdiv.s          &0x00000000,%fp1        # +1 / 0
        rts

#########################################################################
# XDEF **************************************************************** #
#       t_operr(): Handle 060FPLSP OPERR exception during emulation.    #
#                                                                       #
#       This routine is used by the 060FPLSP package.                   #
#                                                                       #
# XREF **************************************************************** #
#       None.                                                           #
#                                                                       #
# INPUT *************************************************************** #
#       fp1 = source operand                                            #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default result                                            #
#       fp1 = unchanged                                                 #
#                                                                       #
# ALGORITHM *********************************************************** #
#       An operand error should occur as the result of transcendental   #
# emulation in the 060FPLSP. If OPERR is disabled, just return a NAN    #
# in fp0. If OPERR is enabled, return the dst operand unscathed in fp0  #
# and the source operand in fp1. Use fp2 to create an OPERR exception   #
# so that the operating system can log the event.                       #
#                                                                       #
#########################################################################

        global          t_operr
t_operr:
        ori.l           &opnan_mask,USER_FPSR(%a6) # set NAN/OPERR/AIOP

        btst            &operr_bit,FPCR_ENABLE(%a6)
        bne.b           operr_ena

# operr is disabled. return a QNAN in fp0
        fmovm.x         qnan(%pc),&0x80         # return QNAN
        rts

# operr is enabled. create an operr exception so the user can record it
# but use fp2 instead. return the dst operand unscathed in fp0.
operr_ena:
        fmovm.x         EXC_FP0(%a6),&0x80      # return fp0 unscathed
        fmov.l          USER_FPCR(%a6),%fpcr
        fmovm.x         &0x04,-(%sp)            # save fp2
        fmov.s          &0x7f800000,%fp2        # load +INF
        fmul.s          &0x00000000,%fp2        # +INF x 0
        fmovm.x         (%sp)+,&0x20            # restore fp2
        rts

pls_huge:
        long            0x7ffe0000,0xffffffff,0xffffffff
mns_huge:
        long            0xfffe0000,0xffffffff,0xffffffff
pls_tiny:
        long            0x00000000,0x80000000,0x00000000
mns_tiny:
        long            0x80000000,0x80000000,0x00000000

#########################################################################
# XDEF **************************************************************** #
#       t_unfl(): Handle 060FPLSP underflow exception during emulation. #
#       t_unfl2(): Handle 060FPLSP underflow exception during           #
#                  emulation. result always positive.                   #
#                                                                       #
#       This routine is used by the 060FPLSP package.                   #
#                                                                       #
# XREF **************************************************************** #
#       None.                                                           #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision source operand               #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default underflow result                                  #
#                                                                       #
# ALGORITHM *********************************************************** #
#       An underflow should occur as the result of transcendental       #
# emulation in the 060FPLSP. Create an underflow by using "fmul"        #
# and two very small numbers of appropriate sign so the operating       #
# system can log the event.                                             #
#                                                                       #
#########################################################################

        global          t_unfl
t_unfl:
        tst.b           SRC_EX(%a0)
        bpl.b           unf_pos

        global          t_unfl2
t_unfl2:
        ori.l           &unfinx_mask+neg_mask,USER_FPSR(%a6) # set N/UNFL/INEX2/AUNFL/AINEX

        fmov.l          USER_FPCR(%a6),%fpcr
        fmovm.x         mns_tiny(%pc),&0x80
        fmul.x          pls_tiny(%pc),%fp0

        fmov.l          %fpsr,%d0
        rol.l           &0x8,%d0
        mov.b           %d0,FPSR_CC(%a6)
        rts
unf_pos:
        ori.w           &unfinx_mask,FPSR_EXCEPT(%a6) # set UNFL/INEX2/AUNFL/AINEX

        fmov.l          USER_FPCR(%a6),%fpcr
        fmovm.x         pls_tiny(%pc),&0x80
        fmul.x          %fp0,%fp0

        fmov.l          %fpsr,%d0
        rol.l           &0x8,%d0
        mov.b           %d0,FPSR_CC(%a6)
        rts

#########################################################################
# XDEF **************************************************************** #
#       t_ovfl(): Handle 060FPLSP overflow exception during emulation.  #
#                 (monadic)                                             #
#       t_ovfl2(): Handle 060FPLSP overflow exception during            #
#                  emulation. result always positive. (dyadic)          #
#       t_ovfl_sc(): Handle 060FPLSP overflow exception during          #
#                    emulation for "fscale".                            #
#                                                                       #
#       This routine is used by the 060FPLSP package.                   #
#                                                                       #
# XREF **************************************************************** #
#       None.                                                           #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision source operand               #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default underflow result                                  #
#                                                                       #
# ALGORITHM *********************************************************** #
#       An overflow should occur as the result of transcendental        #
# emulation in the 060FPLSP. Create an overflow by using "fmul"         #
# and two very lareg numbers of appropriate sign so the operating       #
# system can log the event.                                             #
#       For t_ovfl_sc() we take special care not to lose the INEX2 bit. #
#                                                                       #
#########################################################################

        global          t_ovfl_sc
t_ovfl_sc:
        ori.l           &ovfl_inx_mask,USER_FPSR(%a6) # set OVFL/AOVFL/AINEX

        mov.b           %d0,%d1                 # fetch rnd prec,mode
        andi.b          &0xc0,%d1               # extract prec
        beq.w           ovfl_work

# dst op is a DENORM. we have to normalize the mantissa to see if the
# result would be inexact for the given precision. make a copy of the
# dst so we don't screw up the version passed to us.
        mov.w           LOCAL_EX(%a0),FP_SCR0_EX(%a6)
        mov.l           LOCAL_HI(%a0),FP_SCR0_HI(%a6)
        mov.l           LOCAL_LO(%a0),FP_SCR0_LO(%a6)
        lea             FP_SCR0(%a6),%a0        # pass ptr to FP_SCR0
        movm.l          &0xc080,-(%sp)          # save d0-d1/a0
        bsr.l           norm                    # normalize mantissa
        movm.l          (%sp)+,&0x0103          # restore d0-d1/a0

        cmpi.b          %d1,&0x40               # is precision sgl?
        bne.b           ovfl_sc_dbl             # no; dbl
ovfl_sc_sgl:
        tst.l           LOCAL_LO(%a0)           # is lo lw of sgl set?
        bne.b           ovfl_sc_inx             # yes
        tst.b           3+LOCAL_HI(%a0)         # is lo byte of hi lw set?
        bne.b           ovfl_sc_inx             # yes
        bra.w           ovfl_work               # don't set INEX2
ovfl_sc_dbl:
        mov.l           LOCAL_LO(%a0),%d1       # are any of lo 11 bits of
        andi.l          &0x7ff,%d1              # dbl mantissa set?
        beq.w           ovfl_work               # no; don't set INEX2
ovfl_sc_inx:
        ori.l           &inex2_mask,USER_FPSR(%a6) # set INEX2
        bra.b           ovfl_work               # continue

        global          t_ovfl
t_ovfl:
        ori.w           &ovfinx_mask,FPSR_EXCEPT(%a6) # set OVFL/INEX2/AOVFL/AINEX
ovfl_work:
        tst.b           SRC_EX(%a0)
        bpl.b           ovfl_p
ovfl_m:
        fmov.l          USER_FPCR(%a6),%fpcr
        fmovm.x         mns_huge(%pc),&0x80
        fmul.x          pls_huge(%pc),%fp0

        fmov.l          %fpsr,%d0
        rol.l           &0x8,%d0
        ori.b           &neg_mask,%d0
        mov.b           %d0,FPSR_CC(%a6)
        rts
ovfl_p:
        fmov.l          USER_FPCR(%a6),%fpcr
        fmovm.x         pls_huge(%pc),&0x80
        fmul.x          pls_huge(%pc),%fp0

        fmov.l          %fpsr,%d0
        rol.l           &0x8,%d0
        mov.b           %d0,FPSR_CC(%a6)
        rts

        global          t_ovfl2
t_ovfl2:
        ori.w           &ovfinx_mask,FPSR_EXCEPT(%a6) # set OVFL/INEX2/AOVFL/AINEX
        fmov.l          USER_FPCR(%a6),%fpcr
        fmovm.x         pls_huge(%pc),&0x80
        fmul.x          pls_huge(%pc),%fp0

        fmov.l          %fpsr,%d0
        rol.l           &0x8,%d0
        mov.b           %d0,FPSR_CC(%a6)
        rts

#########################################################################
# XDEF **************************************************************** #
#       t_catch(): Handle 060FPLSP OVFL,UNFL,or INEX2 exception during  #
#                  emulation.                                           #
#       t_catch2(): Handle 060FPLSP OVFL,UNFL,or INEX2 exception during #
#                   emulation.                                          #
#                                                                       #
#       These routines are used by the 060FPLSP package.                #
#                                                                       #
# XREF **************************************************************** #
#       None.                                                           #
#                                                                       #
# INPUT *************************************************************** #
#       fp0 = default underflow or overflow result                      #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default result                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#       If an overflow or underflow occurred during the last            #
# instruction of transcendental 060FPLSP emulation, then it has already #
# occurred and has been logged. Now we need to see if an inexact        #
# exception should occur.                                               #
#                                                                       #
#########################################################################

        global          t_catch2
t_catch2:
        fmov.l          %fpsr,%d0
        or.l            %d0,USER_FPSR(%a6)
        bra.b           inx2_work

        global          t_catch
t_catch:
        fmov.l          %fpsr,%d0
        or.l            %d0,USER_FPSR(%a6)

#########################################################################
# XDEF **************************************************************** #
#       t_inx2(): Handle inexact 060FPLSP exception during emulation.   #
#       t_pinx2(): Handle inexact 060FPLSP exception for "+" results.   #
#       t_minx2(): Handle inexact 060FPLSP exception for "-" results.   #
#                                                                       #
# XREF **************************************************************** #
#       None.                                                           #
#                                                                       #
# INPUT *************************************************************** #
#       fp0 = default result                                            #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default result                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#       The last instruction of transcendental emulation for the        #
# 060FPLSP should be inexact. So, if inexact is enabled, then we create #
# the event here by adding a large and very small number together       #
# so that the operating system can log the event.                       #
#       Must check, too, if the result was zero, in which case we just  #
# set the FPSR bits and return.                                         #
#                                                                       #
#########################################################################

        global          t_inx2
t_inx2:
        fblt.w          t_minx2
        fbeq.w          inx2_zero

        global          t_pinx2
t_pinx2:
        ori.w           &inx2a_mask,FPSR_EXCEPT(%a6) # set INEX2/AINEX
        bra.b           inx2_work

        global          t_minx2
t_minx2:
        ori.l           &inx2a_mask+neg_mask,USER_FPSR(%a6)

inx2_work:
        btst            &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
        bne.b           inx2_work_ena           # yes
        rts
inx2_work_ena:
        fmov.l          USER_FPCR(%a6),%fpcr    # insert user's exceptions
        fmov.s          &0x3f800000,%fp1        # load +1
        fadd.x          pls_tiny(%pc),%fp1      # cause exception
        rts

inx2_zero:
        mov.b           &z_bmask,FPSR_CC(%a6)
        ori.w           &inx2a_mask,2+USER_FPSR(%a6) # set INEX/AINEX
        rts

#########################################################################
# XDEF **************************************************************** #
#       t_extdnrm(): Handle DENORM inputs in 060FPLSP.                  #
#       t_resdnrm(): Handle DENORM inputs in 060FPLSP for "fscale".     #
#                                                                       #
#       This routine is used by the 060FPLSP package.                   #
#                                                                       #
# XREF **************************************************************** #
#       None.                                                           #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to extended precision input operand                #
#                                                                       #
# OUTPUT ************************************************************** #
#       fp0 = default result                                            #
#                                                                       #
# ALGORITHM *********************************************************** #
#       For all functions that have a denormalized input and that       #
# f(x)=x, this is the entry point.                                      #
#       DENORM value is moved using "fmove" which triggers an exception #
# if enabled so the operating system can log the event.                 #
#                                                                       #
#########################################################################

        global          t_extdnrm
t_extdnrm:
        fmov.l          USER_FPCR(%a6),%fpcr
        fmov.x          SRC_EX(%a0),%fp0
        fmov.l          %fpsr,%d0
        ori.l           &unfinx_mask,%d0
        or.l            %d0,USER_FPSR(%a6)
        rts

        global          t_resdnrm
t_resdnrm:
        fmov.l          USER_FPCR(%a6),%fpcr
        fmov.x          SRC_EX(%a0),%fp0
        fmov.l          %fpsr,%d0
        or.l            %d0,USER_FPSR(%a6)
        rts

##########################################

#
# sto_cos:
#       This is used by fsincos library emulation. The correct
# values are already in fp0 and fp1 so we do nothing here.
#
        global          sto_cos
sto_cos:
        rts

##########################################

#
#       dst_qnan --- force result when destination is a NaN
#
        global          dst_qnan
dst_qnan:
        fmov.x          DST(%a1),%fp0
        tst.b           DST_EX(%a1)
        bmi.b           dst_qnan_m
dst_qnan_p:
        mov.b           &nan_bmask,FPSR_CC(%a6)
        rts
dst_qnan_m:
        mov.b           &nan_bmask+neg_bmask,FPSR_CC(%a6)
        rts

#
#       src_qnan --- force result when source is a NaN
#
        global          src_qnan
src_qnan:
        fmov.x          SRC(%a0),%fp0
        tst.b           SRC_EX(%a0)
        bmi.b           src_qnan_m
src_qnan_p:
        mov.b           &nan_bmask,FPSR_CC(%a6)
        rts
src_qnan_m:
        mov.b           &nan_bmask+neg_bmask,FPSR_CC(%a6)
        rts

##########################################

#
#       Native instruction support
#
#       Some systems may need entry points even for 68060 native
#       instructions.  These routines are provided for
#       convenience.
#
        global          _fadds_
_fadds_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.s          0x8(%sp),%fp0           # load sgl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fadd.s          0x8(%sp),%fp0           # fadd w/ sgl src
        rts

        global          _faddd_
_faddd_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.d          0x8(%sp),%fp0           # load dbl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fadd.d          0xc(%sp),%fp0           # fadd w/ dbl src
        rts

        global          _faddx_
_faddx_:
        fmovm.x         0x4(%sp),&0x80          # load ext dst
        fadd.x          0x10(%sp),%fp0          # fadd w/ ext src
        rts

        global          _fsubs_
_fsubs_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.s          0x8(%sp),%fp0           # load sgl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fsub.s          0x8(%sp),%fp0           # fsub w/ sgl src
        rts

        global          _fsubd_
_fsubd_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.d          0x8(%sp),%fp0           # load dbl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fsub.d          0xc(%sp),%fp0           # fsub w/ dbl src
        rts

        global          _fsubx_
_fsubx_:
        fmovm.x         0x4(%sp),&0x80          # load ext dst
        fsub.x          0x10(%sp),%fp0          # fsub w/ ext src
        rts

        global          _fmuls_
_fmuls_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.s          0x8(%sp),%fp0           # load sgl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fmul.s          0x8(%sp),%fp0           # fmul w/ sgl src
        rts

        global          _fmuld_
_fmuld_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.d          0x8(%sp),%fp0           # load dbl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fmul.d          0xc(%sp),%fp0           # fmul w/ dbl src
        rts

        global          _fmulx_
_fmulx_:
        fmovm.x         0x4(%sp),&0x80          # load ext dst
        fmul.x          0x10(%sp),%fp0          # fmul w/ ext src
        rts

        global          _fdivs_
_fdivs_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.s          0x8(%sp),%fp0           # load sgl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fdiv.s          0x8(%sp),%fp0           # fdiv w/ sgl src
        rts

        global          _fdivd_
_fdivd_:
        fmov.l          %fpcr,-(%sp)            # save fpcr
        fmov.l          &0x00000000,%fpcr       # clear fpcr for load
        fmov.d          0x8(%sp),%fp0           # load dbl dst
        fmov.l          (%sp)+,%fpcr            # restore fpcr
        fdiv.d          0xc(%sp),%fp0           # fdiv w/ dbl src
        rts

        global          _fdivx_
_fdivx_:
        fmovm.x         0x4(%sp),&0x80          # load ext dst
        fdiv.x          0x10(%sp),%fp0          # fdiv w/ ext src
        rts

        global          _fabss_
_fabss_:
        fabs.s          0x4(%sp),%fp0           # fabs w/ sgl src
        rts

        global          _fabsd_
_fabsd_:
        fabs.d          0x4(%sp),%fp0           # fabs w/ dbl src
        rts

        global          _fabsx_
_fabsx_:
        fabs.x          0x4(%sp),%fp0           # fabs w/ ext src
        rts

        global          _fnegs_
_fnegs_:
        fneg.s          0x4(%sp),%fp0           # fneg w/ sgl src
        rts

        global          _fnegd_
_fnegd_:
        fneg.d          0x4(%sp),%fp0           # fneg w/ dbl src
        rts

        global          _fnegx_
_fnegx_:
        fneg.x          0x4(%sp),%fp0           # fneg w/ ext src
        rts

        global          _fsqrts_
_fsqrts_:
        fsqrt.s         0x4(%sp),%fp0           # fsqrt w/ sgl src
        rts

        global          _fsqrtd_
_fsqrtd_:
        fsqrt.d         0x4(%sp),%fp0           # fsqrt w/ dbl src
        rts

        global          _fsqrtx_
_fsqrtx_:
        fsqrt.x         0x4(%sp),%fp0           # fsqrt w/ ext src
        rts

        global          _fints_
_fints_:
        fint.s          0x4(%sp),%fp0           # fint w/ sgl src
        rts

        global          _fintd_
_fintd_:
        fint.d          0x4(%sp),%fp0           # fint w/ dbl src
        rts

        global          _fintx_
_fintx_:
        fint.x          0x4(%sp),%fp0           # fint w/ ext src
        rts

        global          _fintrzs_
_fintrzs_:
        fintrz.s        0x4(%sp),%fp0           # fintrz w/ sgl src
        rts

        global          _fintrzd_
_fintrzd_:
        fintrz.d        0x4(%sp),%fp0           # fintrx w/ dbl src
        rts

        global          _fintrzx_
_fintrzx_:
        fintrz.x        0x4(%sp),%fp0           # fintrz w/ ext src
        rts

########################################################################

#########################################################################
# src_zero(): Return signed zero according to sign of src operand.      #
#########################################################################
        global          src_zero
src_zero:
        tst.b           SRC_EX(%a0)             # get sign of src operand
        bmi.b           ld_mzero                # if neg, load neg zero

#
# ld_pzero(): return a positive zero.
#
        global          ld_pzero
ld_pzero:
        fmov.s          &0x00000000,%fp0        # load +0
        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
        rts

# ld_mzero(): return a negative zero.
        global          ld_mzero
ld_mzero:
        fmov.s          &0x80000000,%fp0        # load -0
        mov.b           &neg_bmask+z_bmask,FPSR_CC(%a6) # set 'N','Z' ccode bits
        rts

#########################################################################
# dst_zero(): Return signed zero according to sign of dst operand.      #
#########################################################################
        global          dst_zero
dst_zero:
        tst.b           DST_EX(%a1)             # get sign of dst operand
        bmi.b           ld_mzero                # if neg, load neg zero
        bra.b           ld_pzero                # load positive zero

#########################################################################
# src_inf(): Return signed inf according to sign of src operand.        #
#########################################################################
        global          src_inf
src_inf:
        tst.b           SRC_EX(%a0)             # get sign of src operand
        bmi.b           ld_minf                 # if negative branch

#
# ld_pinf(): return a positive infinity.
#
        global          ld_pinf
ld_pinf:
        fmov.s          &0x7f800000,%fp0        # load +INF
        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'INF' ccode bit
        rts

#
# ld_minf():return a negative infinity.
#
        global          ld_minf
ld_minf:
        fmov.s          &0xff800000,%fp0        # load -INF
        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
        rts

#########################################################################
# dst_inf(): Return signed inf according to sign of dst operand.        #
#########################################################################
        global          dst_inf
dst_inf:
        tst.b           DST_EX(%a1)             # get sign of dst operand
        bmi.b           ld_minf                 # if negative branch
        bra.b           ld_pinf

        global          szr_inf
#################################################################
# szr_inf(): Return +ZERO for a negative src operand or         #
#                   +INF for a positive src operand.            #
#            Routine used for fetox, ftwotox, and ftentox.      #
#################################################################
szr_inf:
        tst.b           SRC_EX(%a0)             # check sign of source
        bmi.b           ld_pzero
        bra.b           ld_pinf

#########################################################################
# sopr_inf(): Return +INF for a positive src operand or                 #
#             jump to operand error routine for a negative src operand. #
#             Routine used for flogn, flognp1, flog10, and flog2.       #
#########################################################################
        global          sopr_inf
sopr_inf:
        tst.b           SRC_EX(%a0)             # check sign of source
        bmi.w           t_operr
        bra.b           ld_pinf

#################################################################
# setoxm1i(): Return minus one for a negative src operand or    #
#             positive infinity for a positive src operand.     #
#             Routine used for fetoxm1.                         #
#################################################################
        global          setoxm1i
setoxm1i:
        tst.b           SRC_EX(%a0)             # check sign of source
        bmi.b           ld_mone
        bra.b           ld_pinf

#########################################################################
# src_one(): Return signed one according to sign of src operand.        #
#########################################################################
        global          src_one
src_one:
        tst.b           SRC_EX(%a0)             # check sign of source
        bmi.b           ld_mone

#
# ld_pone(): return positive one.
#
        global          ld_pone
ld_pone:
        fmov.s          &0x3f800000,%fp0        # load +1
        clr.b           FPSR_CC(%a6)
        rts

#
# ld_mone(): return negative one.
#
        global          ld_mone
ld_mone:
        fmov.s          &0xbf800000,%fp0        # load -1
        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
        rts

ppiby2: long            0x3fff0000, 0xc90fdaa2, 0x2168c235
mpiby2: long            0xbfff0000, 0xc90fdaa2, 0x2168c235

#################################################################
# spi_2(): Return signed PI/2 according to sign of src operand. #
#################################################################
        global          spi_2
spi_2:
        tst.b           SRC_EX(%a0)             # check sign of source
        bmi.b           ld_mpi2

#
# ld_ppi2(): return positive PI/2.
#
        global          ld_ppi2
ld_ppi2:
        fmov.l          %d0,%fpcr
        fmov.x          ppiby2(%pc),%fp0        # load +pi/2
        bra.w           t_pinx2                 # set INEX2

#
# ld_mpi2(): return negative PI/2.
#
        global          ld_mpi2
ld_mpi2:
        fmov.l          %d0,%fpcr
        fmov.x          mpiby2(%pc),%fp0        # load -pi/2
        bra.w           t_minx2                 # set INEX2

####################################################
# The following routines give support for fsincos. #
####################################################

#
# ssincosz(): When the src operand is ZERO, store a one in the
#             cosine register and return a ZERO in fp0 w/ the same sign
#             as the src operand.
#
        global          ssincosz
ssincosz:
        fmov.s          &0x3f800000,%fp1
        tst.b           SRC_EX(%a0)             # test sign
        bpl.b           sincoszp
        fmov.s          &0x80000000,%fp0        # return sin result in fp0
        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6)
        rts
sincoszp:
        fmov.s          &0x00000000,%fp0        # return sin result in fp0
        mov.b           &z_bmask,FPSR_CC(%a6)
        rts

#
# ssincosi(): When the src operand is INF, store a QNAN in the cosine
#             register and jump to the operand error routine for negative
#             src operands.
#
        global          ssincosi
ssincosi:
        fmov.x          qnan(%pc),%fp1          # load NAN
        bra.w           t_operr

#
# ssincosqnan(): When the src operand is a QNAN, store the QNAN in the cosine
#                register and branch to the src QNAN routine.
#
        global          ssincosqnan
ssincosqnan:
        fmov.x          LOCAL_EX(%a0),%fp1
        bra.w           src_qnan

########################################################################

        global          smod_sdnrm
        global          smod_snorm
smod_sdnrm:
smod_snorm:
        mov.b           DTAG(%a6),%d1
        beq.l           smod
        cmpi.b          %d1,&ZERO
        beq.w           smod_zro
        cmpi.b          %d1,&INF
        beq.l           t_operr
        cmpi.b          %d1,&DENORM
        beq.l           smod
        bra.l           dst_qnan

        global          smod_szero
smod_szero:
        mov.b           DTAG(%a6),%d1
        beq.l           t_operr
        cmpi.b          %d1,&ZERO
        beq.l           t_operr
        cmpi.b          %d1,&INF
        beq.l           t_operr
        cmpi.b          %d1,&DENORM
        beq.l           t_operr
        bra.l           dst_qnan

        global          smod_sinf
smod_sinf:
        mov.b           DTAG(%a6),%d1
        beq.l           smod_fpn
        cmpi.b          %d1,&ZERO
        beq.l           smod_zro
        cmpi.b          %d1,&INF
        beq.l           t_operr
        cmpi.b          %d1,&DENORM
        beq.l           smod_fpn
        bra.l           dst_qnan

smod_zro:
srem_zro:
        mov.b           SRC_EX(%a0),%d1         # get src sign
        mov.b           DST_EX(%a1),%d0         # get dst sign
        eor.b           %d0,%d1                 # get qbyte sign
        andi.b          &0x80,%d1
        mov.b           %d1,FPSR_QBYTE(%a6)
        tst.b           %d0
        bpl.w           ld_pzero
        bra.w           ld_mzero

smod_fpn:
srem_fpn:
        clr.b           FPSR_QBYTE(%a6)
        mov.l           %d0,-(%sp)
        mov.b           SRC_EX(%a0),%d1         # get src sign
        mov.b           DST_EX(%a1),%d0         # get dst sign
        eor.b           %d0,%d1                 # get qbyte sign
        andi.b          &0x80,%d1
        mov.b           %d1,FPSR_QBYTE(%a6)
        cmpi.b          DTAG(%a6),&DENORM
        bne.b           smod_nrm
        lea             DST(%a1),%a0
        mov.l           (%sp)+,%d0
        bra             t_resdnrm
smod_nrm:
        fmov.l          (%sp)+,%fpcr
        fmov.x          DST(%a1),%fp0
        tst.b           DST_EX(%a1)
        bmi.b           smod_nrm_neg
        rts

smod_nrm_neg:
        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' code
        rts

#########################################################################
        global          srem_snorm
        global          srem_sdnrm
srem_sdnrm:
srem_snorm:
        mov.b           DTAG(%a6),%d1
        beq.l           srem
        cmpi.b          %d1,&ZERO
        beq.w           srem_zro
        cmpi.b          %d1,&INF
        beq.l           t_operr
        cmpi.b          %d1,&DENORM
        beq.l           srem
        bra.l           dst_qnan

        global          srem_szero
srem_szero:
        mov.b           DTAG(%a6),%d1
        beq.l           t_operr
        cmpi.b          %d1,&ZERO
        beq.l           t_operr
        cmpi.b          %d1,&INF
        beq.l           t_operr
        cmpi.b          %d1,&DENORM
        beq.l           t_operr
        bra.l           dst_qnan

        global          srem_sinf
srem_sinf:
        mov.b           DTAG(%a6),%d1
        beq.w           srem_fpn
        cmpi.b          %d1,&ZERO
        beq.w           srem_zro
        cmpi.b          %d1,&INF
        beq.l           t_operr
        cmpi.b          %d1,&DENORM
        beq.l           srem_fpn
        bra.l           dst_qnan

#########################################################################

        global          sscale_snorm
        global          sscale_sdnrm
sscale_snorm:
sscale_sdnrm:
        mov.b           DTAG(%a6),%d1
        beq.l           sscale
        cmpi.b          %d1,&ZERO
        beq.l           dst_zero
        cmpi.b          %d1,&INF
        beq.l           dst_inf
        cmpi.b          %d1,&DENORM
        beq.l           sscale
        bra.l           dst_qnan

        global          sscale_szero
sscale_szero:
        mov.b           DTAG(%a6),%d1
        beq.l           sscale
        cmpi.b          %d1,&ZERO
        beq.l           dst_zero
        cmpi.b          %d1,&INF
        beq.l           dst_inf
        cmpi.b          %d1,&DENORM
        beq.l           sscale
        bra.l           dst_qnan

        global          sscale_sinf
sscale_sinf:
        mov.b           DTAG(%a6),%d1
        beq.l           t_operr
        cmpi.b          %d1,&QNAN
        beq.l           dst_qnan
        bra.l           t_operr

########################################################################

        global          sop_sqnan
sop_sqnan:
        mov.b           DTAG(%a6),%d1
        cmpi.b          %d1,&QNAN
        beq.l           dst_qnan
        bra.l           src_qnan

#########################################################################
# norm(): normalize the mantissa of an extended precision input. the    #
#         input operand should not be normalized already.               #
#                                                                       #
# XDEF **************************************************************** #
#       norm()                                                          #
#                                                                       #
# XREF **************************************************************** #
#       none                                                            #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer fp extended precision operand to normalize         #
#                                                                       #
# OUTPUT ************************************************************** #
#       d0 = number of bit positions the mantissa was shifted           #
#       a0 = the input operand's mantissa is normalized; the exponent   #
#            is unchanged.                                              #
#                                                                       #
#########################################################################
        global          norm
norm:
        mov.l           %d2, -(%sp)             # create some temp regs
        mov.l           %d3, -(%sp)

        mov.l           FTEMP_HI(%a0), %d0      # load hi(mantissa)
        mov.l           FTEMP_LO(%a0), %d1      # load lo(mantissa)

        bfffo           %d0{&0:&32}, %d2        # how many places to shift?
        beq.b           norm_lo                 # hi(man) is all zeroes!

norm_hi:
        lsl.l           %d2, %d0                # left shift hi(man)
        bfextu          %d1{&0:%d2}, %d3        # extract lo bits

        or.l            %d3, %d0                # create hi(man)
        lsl.l           %d2, %d1                # create lo(man)

        mov.l           %d0, FTEMP_HI(%a0)      # store new hi(man)
        mov.l           %d1, FTEMP_LO(%a0)      # store new lo(man)

        mov.l           %d2, %d0                # return shift amount

        mov.l           (%sp)+, %d3             # restore temp regs
        mov.l           (%sp)+, %d2

        rts

norm_lo:
        bfffo           %d1{&0:&32}, %d2        # how many places to shift?
        lsl.l           %d2, %d1                # shift lo(man)
        add.l           &32, %d2                # add 32 to shft amount

        mov.l           %d1, FTEMP_HI(%a0)      # store hi(man)
        clr.l           FTEMP_LO(%a0)           # lo(man) is now zero

        mov.l           %d2, %d0                # return shift amount

        mov.l           (%sp)+, %d3             # restore temp regs
        mov.l           (%sp)+, %d2

        rts

#########################################################################
# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO     #
#               - returns corresponding optype tag                      #
#                                                                       #
# XDEF **************************************************************** #
#       unnorm_fix()                                                    #
#                                                                       #
# XREF **************************************************************** #
#       norm() - normalize the mantissa                                 #
#                                                                       #
# INPUT *************************************************************** #
#       a0 = pointer to unnormalized extended precision number          #
#                                                                       #
# OUTPUT ************************************************************** #
#       d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO  #
#       a0 = input operand has been converted to a norm, denorm, or     #
#            zero; both the exponent and mantissa are changed.          #
#                                                                       #
#########################################################################

        global          unnorm_fix
unnorm_fix:
        bfffo           FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
        bne.b           unnorm_shift            # hi(man) is not all zeroes

#
# hi(man) is all zeroes so see if any bits in lo(man) are set
#
unnorm_chk_lo:
        bfffo           FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
        beq.w           unnorm_zero             # yes

        add.w           &32, %d0                # no; fix shift distance

#
# d0 = # shifts needed for complete normalization
#
unnorm_shift:
        clr.l           %d1                     # clear top word
        mov.w           FTEMP_EX(%a0), %d1      # extract exponent
        and.w           &0x7fff, %d1            # strip off sgn

        cmp.w           %d0, %d1                # will denorm push exp < 0?
        bgt.b           unnorm_nrm_zero         # yes; denorm only until exp = 0

#
# exponent would not go < 0. therefore, number stays normalized
#
        sub.w           %d0, %d1                # shift exponent value
        mov.w           FTEMP_EX(%a0), %d0      # load old exponent
        and.w           &0x8000, %d0            # save old sign
        or.w            %d0, %d1                # {sgn,new exp}
        mov.w           %d1, FTEMP_EX(%a0)      # insert new exponent

        bsr.l           norm                    # normalize UNNORM

        mov.b           &NORM, %d0              # return new optype tag
        rts

#
# exponent would go < 0, so only denormalize until exp = 0
#
unnorm_nrm_zero:
        cmp.b           %d1, &32                # is exp <= 32?
        bgt.b           unnorm_nrm_zero_lrg     # no; go handle large exponent

        bfextu          FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
        mov.l           %d0, FTEMP_HI(%a0)      # save new hi(man)

        mov.l           FTEMP_LO(%a0), %d0      # fetch old lo(man)
        lsl.l           %d1, %d0                # extract new lo(man)
        mov.l           %d0, FTEMP_LO(%a0)      # save new lo(man)

        and.w           &0x8000, FTEMP_EX(%a0)  # set exp = 0

        mov.b           &DENORM, %d0            # return new optype tag
        rts

#
# only mantissa bits set are in lo(man)
#
unnorm_nrm_zero_lrg:
        sub.w           &32, %d1                # adjust shft amt by 32

        mov.l           FTEMP_LO(%a0), %d0      # fetch old lo(man)
        lsl.l           %d1, %d0                # left shift lo(man)

        mov.l           %d0, FTEMP_HI(%a0)      # store new hi(man)
        clr.l           FTEMP_LO(%a0)           # lo(man) = 0

        and.w           &0x8000, FTEMP_EX(%a0)  # set exp = 0

        mov.b           &DENORM, %d0            # return new optype tag
        rts

#
# whole mantissa is zero so this UNNORM is actually a zero
#
unnorm_zero:
        and.w           &0x8000, FTEMP_EX(%a0)  # force exponent to zero

        mov.b           &ZERO, %d0              # fix optype tag
        rts

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.