*       $NetBSD: x_snan.sa,v 1.4 2001/09/16 16:34:32 wiz 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.

*
*       x_snan.sa 3.3 7/1/91
*
* fpsp_snan --- FPSP handler for signalling NAN exception
*
* SNAN for float -> integer conversions (integer conversion of
* an SNAN) is a non-maskable run-time exception.
*
* For trap disabled the 040 does the following:
* If the dest data format is s, d, or x, then the SNAN bit in the NAN
* is set to one and the resulting non-signaling NAN (truncated if
* necessary) is transferred to the dest.  If the dest format is b, w,
* or l, then garbage is written to the dest (actually the upper 32 bits
* of the mantissa are sent to the integer unit).
*
* For trap enabled the 040 does the following:
* If the inst is move_out, then the results are the same as for trap
* disabled with the exception posted.  If the instruction is not move_
* out, the dest. is not modified, and the exception is posted.
*

X_SNAN  IDNT    2,1 Motorola 040 Floating Point Software Package

       section 8

       include fpsp.h

       xref    get_fline
       xref    mem_write
       xref    real_snan
       xref    real_inex
       xref    fpsp_done
       xref    reg_dest

       xdef    fpsp_snan
fpsp_snan:
       link            a6,#-LOCAL_SIZE
       fsave           -(a7)
       movem.l         d0-d1/a0-a1,USER_DA(a6)
       fmovem.x        fp0-fp3,USER_FP0(a6)
       fmovem.l        fpcr/fpsr/fpiar,USER_FPCR(a6)

*
* Check if trap enabled
*
       btst.b          #snan_bit,FPCR_ENABLE(a6)
       bne.b           ena             ;If enabled, then branch

       bsr.l           move_out        ;else SNAN disabled
*
* It is possible to have an inex1 exception with the
* snan.  If the inex enable bit is set in the FPCR, and either
* inex2 or inex1 occurred, we must clean up and branch to the
* real inex handler.
*
ck_inex:
       move.b  FPCR_ENABLE(a6),d0
       and.b   FPSR_EXCEPT(a6),d0
       andi.b  #$3,d0
       beq.w   end_snan
*
* Inexact enabled and reported, and we must take an inexact exception.
*
take_inex:
       move.b          #INEX_VEC,EXC_VEC+1(a6)
       movem.l         USER_DA(a6),d0-d1/a0-a1
       fmovem.x        USER_FP0(a6),fp0-fp3
       fmovem.l        USER_FPCR(a6),fpcr/fpsr/fpiar
       frestore        (a7)+
       unlk            a6
       bra.l           real_inex
*
* SNAN is enabled.  Check if inst is move_out.
* Make any corrections to the 040 output as necessary.
*
ena:
       btst.b          #5,CMDREG1B(a6) ;if set, inst is move out
       beq.w           not_out

       bsr.l           move_out

report_snan:
       move.b          (a7),VER_TMP(a6)
       cmpi.b          #VER_40,(a7)    ;test for orig unimp frame
       bne.b           ck_rev
       moveq.l         #13,d0          ;need to zero 14 lwords
       bra.b           rep_con
ck_rev:
       moveq.l         #11,d0          ;need to zero 12 lwords
rep_con:
       clr.l           (a7)
loop1:
       clr.l           -(a7)           ;clear and dec a7
       dbra.w          d0,loop1
       move.b          VER_TMP(a6),(a7) ;format a busy frame
       move.b          #BUSY_SIZE-4,1(a7)
       move.l          USER_FPSR(a6),FPSR_SHADOW(a6)
       or.l            #sx_mask,E_BYTE(a6)
       movem.l         USER_DA(a6),d0-d1/a0-a1
       fmovem.x        USER_FP0(a6),fp0-fp3
       fmovem.l        USER_FPCR(a6),fpcr/fpsr/fpiar
       frestore        (a7)+
       unlk            a6
       bra.l           real_snan
*
* Exit snan handler by expanding the unimp frame into a busy frame
*
end_snan:
       bclr.b          #E1,E_BYTE(a6)

       move.b          (a7),VER_TMP(a6)
       cmpi.b          #VER_40,(a7)    ;test for orig unimp frame
       bne.b           ck_rev2
       moveq.l         #13,d0          ;need to zero 14 lwords
       bra.b           rep_con2
ck_rev2:
       moveq.l         #11,d0          ;need to zero 12 lwords
rep_con2:
       clr.l           (a7)
loop2:
       clr.l           -(a7)           ;clear and dec a7
       dbra.w          d0,loop2
       move.b          VER_TMP(a6),(a7) ;format a busy frame
       move.b          #BUSY_SIZE-4,1(a7) ;write busy size
       move.l          USER_FPSR(a6),FPSR_SHADOW(a6)
       or.l            #sx_mask,E_BYTE(a6)
       movem.l         USER_DA(a6),d0-d1/a0-a1
       fmovem.x        USER_FP0(a6),fp0-fp3
       fmovem.l        USER_FPCR(a6),fpcr/fpsr/fpiar
       frestore        (a7)+
       unlk            a6
       bra.l           fpsp_done

*
* Move_out
*
move_out:
       move.l          EXC_EA(a6),a0   ;get <ea> from exc frame

       bfextu          CMDREG1B(a6){3:3},d0 ;move rx field to d0{2:0}
       tst.l           d0              ;check for long
       beq.b           sto_long        ;branch if move_out long

       cmpi.l          #4,d0           ;check for word
       beq.b           sto_word        ;branch if move_out word

       cmpi.l          #6,d0           ;check for byte
       beq.b           sto_byte        ;branch if move_out byte

*
* Not byte, word or long
*
       rts
*
* Get the 32 most significant bits of etemp mantissa
*
sto_long:
       move.l          ETEMP_HI(a6),d1
       move.l          #4,d0           ;load byte count
*
* Set signalling nan bit
*
       bset.l          #30,d1
*
* Store to the users destination address
*
       tst.l           a0              ;check if <ea> is 0
       beq.b           wrt_dn          ;destination is a data register

       move.l          d1,-(a7)        ;move the snan onto the stack
       move.l          a0,a1           ;load dest addr into a1
       move.l          a7,a0           ;load src addr of snan into a0
       bsr.l           mem_write       ;write snan to user memory
       move.l          (a7)+,d1        ;clear off stack
       rts
*
* Get the 16 most significant bits of etemp mantissa
*
sto_word:
       move.l          ETEMP_HI(a6),d1
       move.l          #2,d0           ;load byte count
*
* Set signalling nan bit
*
       bset.l          #30,d1
*
* Store to the users destination address
*
       tst.l           a0              ;check if <ea> is 0
       beq.b           wrt_dn          ;destination is a data register

       move.l          d1,-(a7)        ;move the snan onto the stack
       move.l          a0,a1           ;load dest addr into a1
       move.l          a7,a0           ;point to low word
       bsr.l           mem_write       ;write snan to user memory
       move.l          (a7)+,d1        ;clear off stack
       rts
*
* Get the 8 most significant bits of etemp mantissa
*
sto_byte:
       move.l          ETEMP_HI(a6),d1
       move.l          #1,d0           ;load byte count
*
* Set signalling nan bit
*
       bset.l          #30,d1
*
* Store to the users destination address
*
       tst.l           a0              ;check if <ea> is 0
       beq.b           wrt_dn          ;destination is a data register
       move.l          d1,-(a7)        ;move the snan onto the stack
       move.l          a0,a1           ;load dest addr into a1
       move.l          a7,a0           ;point to source byte
       bsr.l           mem_write       ;write snan to user memory
       move.l          (a7)+,d1        ;clear off stack
       rts

*
*       wrt_dn --- write to a data register
*
*       We get here with D1 containing the data to write and D0 the
*       number of bytes to write: 1=byte,2=word,4=long.
*
wrt_dn:
       move.l          d1,L_SCR1(a6)   ;data
       move.l          d0,-(a7)        ;size
       bsr.l           get_fline       ;returns fline word in d0
       move.l          d0,d1
       andi.l          #$7,d1          ;d1 now holds register number
       move.l          (sp)+,d0        ;get original size
       cmpi.l          #4,d0
       beq.b           wrt_long
       cmpi.l          #2,d0
       bne.b           wrt_byte
wrt_word:
       or.l            #$8,d1
       bra.l           reg_dest
wrt_long:
       or.l            #$10,d1
       bra.l           reg_dest
wrt_byte:
       bra.l           reg_dest
*
* Check if it is a src nan or dst nan
*
not_out:
       move.l          DTAG(a6),d0
       bfextu          d0{0:3},d0      ;isolate dtag in lsbs

       cmpi.b          #3,d0           ;check for nan in destination
       bne.b           issrc           ;destination nan has priority
dst_nan:
       btst.b          #6,FPTEMP_HI(a6) ;check if dest nan is an snan
       bne.b           issrc           ;no, so check source for snan
       move.w          FPTEMP_EX(a6),d0
       bra.b           cont
issrc:
       move.w          ETEMP_EX(a6),d0
cont:
       btst.l          #15,d0          ;test for sign of snan
       beq.b           clr_neg
       bset.b          #neg_bit,FPSR_CC(a6)
       bra.w           report_snan
clr_neg:
       bclr.b          #neg_bit,FPSR_CC(a6)
       bra.w           report_snan

       end