*       $NetBSD: l_support.sa,v 1.3 1994/10/26 07:49:16 cgd Exp $

*       MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
*       M68000 Hi-Performance Microprocessor Division
*       M68040 Software Package
*
*       M68040 Software Package Copyright (c) 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.

*
*       l_support.sa 1.2 5/1/91
*

L_SUPPORT    IDNT    2,1 Motorola 040 Floating Point Software Package

       section    8

mns_one  dc.l $bfff0000,$80000000,$00000000
pls_one  dc.l $3fff0000,$80000000,$00000000
pls_inf  dc.l $7fff0000,$00000000,$00000000
pls_huge dc.l $7ffe0000,$ffffffff,$ffffffff
mns_huge dc.l $fffe0000,$ffffffff,$ffffffff
pls_tiny dc.l $00000000,$80000000,$00000000
mns_tiny dc.l $80000000,$80000000,$00000000
small    dc.l $20000000,$80000000,$00000000
pls_zero dc.l $00000000,$00000000,$00000000

       include l_fpsp.h

*
*       tag --- determine the type of an extended precision operand
*
*       The tag values returned match the way the 68040 would have
*       tagged them.
*
*       Input:  a0 points to operand
*
*       Output  d0.b    = $00 norm
*                         $20 zero
*                         $40 inf
*                         $60 nan
*                         $80 denorm
*               All other registers are unchanged
*
       xdef    tag
tag:
       move.w  LOCAL_EX(a0),d0
       andi.w  #$7fff,d0
       beq.b   chk_zro
       cmpi.w  #$7fff,d0
       beq.b   chk_inf
tag_nrm:
       clr.b   d0
       rts
tag_nan:
       move.b  #$60,d0
       rts
tag_dnrm:
       move.b  #$80,d0
       rts
chk_zro:
       btst.b  #7,LOCAL_HI(a0) # check if J-bit is set
       bne.b   tag_nrm
       tst.l   LOCAL_HI(a0)
       bne.b   tag_dnrm
       tst.l   LOCAL_LO(a0)
       bne.b   tag_dnrm
tag_zero:
       move.b  #$20,d0
       rts
chk_inf:
       tst.l   LOCAL_HI(a0)
       bne.b   tag_nan
       tst.l   LOCAL_LO(a0)
       bne.b   tag_nan
tag_inf:
       move.b  #$40,d0
       rts

*
*       t_dz, t_dz2 --- divide by zero exception
*
* t_dz2 is used by monadic functions such as flogn (from do_func).
* t_dz is used by monadic functions such as satanh (from the
* transcendental function).
*
       xdef    t_dz2
t_dz2:
       fmovem.x        mns_one,fp0
       fmove.l d1,fpcr
       fdiv.x          pls_zero,fp0
       rts

       xdef    t_dz
t_dz:
       btst.b  #sign_bit,ETEMP_EX(a6)  ;check sign for neg or pos
       beq.b   p_inf                   ;branch if pos sign
m_inf:
       fmovem.x mns_one,fp0
       fmove.l d1,fpcr
       fdiv.x          pls_zero,fp0
       rts
p_inf:
       fmovem.x pls_one,fp0
       fmove.l d1,fpcr
       fdiv.x          pls_zero,fp0
       rts
*
*       t_operr --- Operand Error exception
*
       xdef    t_operr
t_operr:
       fmovem.x        pls_inf,fp0
       fmove.l d1,fpcr
       fmul.x          pls_zero,fp0
       rts

*
*       t_unfl --- UNFL exception
*
       xdef    t_unfl
t_unfl:
       btst.b  #sign_bit,ETEMP(a6)
       beq.b   unf_pos
unf_neg:
       fmovem.x        mns_tiny,fp0
       fmove.l d1,fpcr
       fmul.x  pls_tiny,fp0
       rts

unf_pos:
       fmovem.x        pls_tiny,fp0
       fmove.l d1,fpcr
       fmul.x  fp0,fp0
       rts
*
*       t_ovfl --- OVFL exception
*
*       t_ovfl is called as an exit for monadic functions.  t_ovfl2
*       is for dyadic exits.
*
       xdef            t_ovfl
t_ovfl:
       xdef            t_ovfl2
       move.l          d1,USER_FPCR(a6)        user's control register
       move.l          #ovfinx_mask,d0
       bra.b           t_work
t_ovfl2:
       move.l          #ovfl_inx_mask,d0
t_work:
       btst.b          #sign_bit,ETEMP(a6)
       beq.b           ovf_pos
ovf_neg:
       fmovem.x        mns_huge,fp0
       fmove.l         USER_FPCR(a6),fpcr
       fmul.x          pls_huge,fp0
       fmove.l         fpsr,d1
       or.l            d1,d0
       fmove.l         d0,fpsr
       rts
ovf_pos:
       fmovem.x        pls_huge,fp0
       fmove.l         USER_FPCR(a6),fpcr
       fmul.x          pls_huge,fp0
       fmove.l         fpsr,d1
       or.l            d1,d0
       fmove.l         d0,fpsr
       rts
*
*       t_inx2 --- INEX2 exception (correct fpcr is in USER_FPCR(a6))
*
       xdef    t_inx2
t_inx2:
       fmove.l         fpsr,USER_FPSR(a6)      capture incoming fpsr
       fmove.l         USER_FPCR(a6),fpcr
*
* create an inex2 exception by adding two numbers with very different exponents
* do the add in fp1 so as to not disturb the result sitting in fp0
*
       fmove.x         pls_one,fp1
       fadd.x          small,fp1
*
       or.l    #inx2a_mask,USER_FPSR(a6) ;set INEX2, AINEX
       fmove.l USER_FPSR(a6),fpsr
       rts
*
*       t_frcinx --- Force Inex2 (for monadic functions)
*
       xdef    t_frcinx
t_frcinx:
       fmove.l         fpsr,USER_FPSR(a6)      capture incoming fpsr
       fmove.l         d1,fpcr
*
* create an inex2 exception by adding two numbers with very different exponents
* do the add in fp1 so as to not disturb the result sitting in fp0
*
       fmove.x         pls_one,fp1
       fadd.x          small,fp1
*
       or.l    #inx2a_mask,USER_FPSR(a6) ;set INEX2, AINEX
       btst.b  #unfl_bit,FPSR_EXCEPT(a6) ;test for unfl bit set
       beq.b   no_uacc1                ;if clear, do not set aunfl
       bset.b  #aunfl_bit,FPSR_AEXCEPT(a6)
no_uacc1:
       fmove.l USER_FPSR(a6),fpsr
       rts
*
*       dst_nan --- force result when destination is a NaN
*
       xdef    dst_nan
dst_nan:
       fmove.l USER_FPCR(a6),fpcr
       fmove.x FPTEMP(a6),fp0
       rts

*
*       src_nan --- force result when source is a NaN
*
       xdef    src_nan
src_nan:
       fmove.l USER_FPCR(a6),fpcr
       fmove.x ETEMP(a6),fp0
       rts
*
*       mon_nan --- force result when source is a NaN (monadic version)
*
*       This is the same as src_nan except that the user's fpcr comes
*       in via d1, not USER_FPCR(a6).
*
       xdef    mon_nan
mon_nan:
       fmove.l d1,fpcr
       fmove.x ETEMP(a6),fp0
       rts
*
*       t_extdnrm, t_resdnrm --- generate results for denorm inputs
*
*       For all functions that have a denormalized input and that f(x)=x,
*       this is the entry point.
*
       xdef    t_extdnrm
t_extdnrm:
       fmove.l d1,fpcr
       fmove.x LOCAL_EX(a0),fp0
       fmove.l         fpsr,d0
       or.l            #unfinx_mask,d0
       fmove.l         d0,fpsr
       rts

       xdef    t_resdnrm
t_resdnrm:
       fmove.l USER_FPCR(a6),fpcr
       fmove.x LOCAL_EX(a0),fp0
       fmove.l         fpsr,d0
       or.l            #unfl_mask,d0
       fmove.l         d0,fpsr
       rts
*
*
*
       xdef    t_avoid_unsupp
t_avoid_unsupp:
       fmove.x fp0,fp0
       rts

       xdef    sto_cos
sto_cos:
       fmovem.x LOCAL_EX(a0),fp1
       rts
*
*       Native instruction support
*
*       Some systems may need entry points even for 68040 native
*       instructions.  These routines are provided for
*       convenience.
*
       xdef    sadd
sadd:
       fmovem.x        FPTEMP(a6),fp0
       fmove.l USER_FPCR(a6),fpcr
       fadd.x  ETEMP(a6),fp0
       rts

       xdef    ssub
ssub:
       fmovem.x        FPTEMP(a6),fp0
       fmove.l USER_FPCR(a6),fpcr
       fsub.x  ETEMP(a6),fp0
       rts

       xdef    smul
smul:
       fmovem.x        FPTEMP(a6),fp0
       fmove.l USER_FPCR(a6),fpcr
       fmul.x  ETEMP(a6),fp0
       rts

       xdef    sdiv
sdiv:
       fmovem.x        FPTEMP(a6),fp0
       fmove.l USER_FPCR(a6),fpcr
       fdiv.x  ETEMP(a6),fp0
       rts

       xdef    sabs
sabs:
       fmovem.x        ETEMP(a6),fp0
       fmove.l d1,fpcr
       fabs.x  fp0
       rts

       xdef    sneg
sneg:
       fmovem.x        ETEMP(a6),fp0
       fmove.l d1,fpcr
       fneg.x  fp0
       rts

       xdef    ssqrt
ssqrt:
       fmovem.x        ETEMP(a6),fp0
       fmove.l d1,fpcr
       fsqrt.x fp0
       rts

*
*       l_sint,l_sintrz,l_sintd --- special wrapper for fint and fintrz
*
*       On entry, move the user's FPCR to USER_FPCR.
*
*       On return from, we need to pickup the INEX2/AINEX bits
*       that are in USER_FPSR.
*
       xref    sint
       xref    sintrz
       xref    sintd

       xdef    l_sint
l_sint:
       move.l  d1,USER_FPCR(a6)
       jsr     sint
       fmove.l fpsr,d0
       or.l    USER_FPSR(a6),d0
       fmove.l d0,fpsr
       rts

       xdef    l_sintrz
l_sintrz:
       move.l  d1,USER_FPCR(a6)
       jsr     sintrz
       fmove.l fpsr,d0
       or.l    USER_FPSR(a6),d0
       fmove.l d0,fpsr
       rts

       xdef    l_sintd
l_sintd:
       move.l  d1,USER_FPCR(a6)
       jsr     sintd
       fmove.l fpsr,d0
       or.l    USER_FPSR(a6),d0
       fmove.l d0,fpsr
       rts

       end