summaryrefslogtreecommitdiff
path: root/sys/arch/m68k/fpsp/x_operr.sa
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/m68k/fpsp/x_operr.sa')
-rw-r--r--sys/arch/m68k/fpsp/x_operr.sa381
1 files changed, 381 insertions, 0 deletions
diff --git a/sys/arch/m68k/fpsp/x_operr.sa b/sys/arch/m68k/fpsp/x_operr.sa
new file mode 100644
index 00000000000..9e1292d108a
--- /dev/null
+++ b/sys/arch/m68k/fpsp/x_operr.sa
@@ -0,0 +1,381 @@
+* $NetBSD: x_operr.sa,v 1.4 1994/10/26 07:50:24 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.
+
+*
+* x_operr.sa 3.5 7/1/91
+*
+* fpsp_operr --- FPSP handler for operand error exception
+*
+* See 68040 User's Manual pp. 9-44f
+*
+* Note 1: For trap disabled 040 does the following:
+* If the dest is a fp reg, then an extended precision non_signaling
+* NAN is stored in the dest reg. If the dest format is b, w, or l and
+* the source op is a NAN, then garbage is stored as the result (actually
+* the upper 32 bits of the mantissa are sent to the integer unit). If
+* the dest format is integer (b, w, l) and the operr is caused by
+* integer overflow, or the source op is inf, then the result stored is
+* garbage.
+* There are three cases in which operr is incorrectly signaled on the
+* 040. This occurs for move_out of format b, w, or l for the largest
+* negative integer (-2^7 for b, -2^15 for w, -2^31 for l).
+*
+* On opclass = 011 fmove.(b,w,l) that causes a conversion
+* overflow -> OPERR, the exponent in wbte (and fpte) is:
+* byte 56 - (62 - exp)
+* word 48 - (62 - exp)
+* long 32 - (62 - exp)
+*
+* where exp = (true exp) - 1
+*
+* So, wbtemp and fptemp will contain the following on erroneoulsy
+* signalled operr:
+* fpts = 1
+* fpte = $4000 (15 bit externally)
+* byte fptm = $ffffffff ffffff80
+* word fptm = $ffffffff ffff8000
+* long fptm = $ffffffff 80000000
+*
+* Note 2: For trap enabled 040 does the following:
+* If the inst is move_out, then same as Note 1.
+* If the inst is not move_out, the dest is not modified.
+* The exceptional operand is not defined for integer overflow
+* during a move_out.
+*
+
+X_OPERR IDNT 2,1 Motorola 040 Floating Point Software Package
+
+ section 8
+
+ include fpsp.h
+
+ xref mem_write
+ xref real_operr
+ xref real_inex
+ xref get_fline
+ xref fpsp_done
+ xref reg_dest
+
+ xdef fpsp_operr
+fpsp_operr:
+*
+ 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 this is an opclass 3 instruction.
+* If so, fall through, else branch to operr_end
+*
+ btst.b #TFLAG,T_BYTE(a6)
+ beq.b operr_end
+
+*
+* If the destination size is B,W,or L, the operr must be
+* handled here.
+*
+ move.l CMDREG1B(a6),d0
+ bfextu d0{3:3},d0 ;0=long, 4=word, 6=byte
+ tst.b d0 ;determine size; check long
+ beq.w operr_long
+ cmpi.b #4,d0 ;check word
+ beq.w operr_word
+ cmpi.b #6,d0 ;check byte
+ beq.w operr_byte
+
+*
+* The size is not B,W,or L, so the operr is handled by the
+* kernel handler. Set the operr bits and clean up, leaving
+* only the integer exception frame on the stack, and the
+* fpu in the original exceptional state.
+*
+operr_end:
+ bset.b #operr_bit,FPSR_EXCEPT(a6)
+ bset.b #aiop_bit,FPSR_AEXCEPT(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_operr
+
+operr_long:
+ moveq.l #4,d1 ;write size to d1
+ move.b STAG(a6),d0 ;test stag for nan
+ andi.b #$e0,d0 ;clr all but tag
+ cmpi.b #$60,d0 ;check for nan
+ beq operr_nan
+ cmpi.l #$80000000,FPTEMP_LO(a6) ;test if ls lword is special
+ bne.b chklerr ;if not equal, check for incorrect operr
+ bsr check_upper ;check if exp and ms mant are special
+ tst.l d0
+ bne.b chklerr ;if d0 is true, check for incorrect operr
+ move.l #$80000000,d0 ;store special case result
+ bsr operr_store
+ bra.w not_enabled ;clean and exit
+*
+* CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
+*
+chklerr:
+ move.w FPTEMP_EX(a6),d0
+ and.w #$7FFF,d0 ;ignore sign bit
+ cmp.w #$3FFE,d0 ;this is the only possible exponent value
+ bne.b chklerr2
+fixlong:
+ move.l FPTEMP_LO(a6),d0
+ bsr operr_store
+ bra.w not_enabled
+chklerr2:
+ move.w FPTEMP_EX(a6),d0
+ and.w #$7FFF,d0 ;ignore sign bit
+ cmp.w #$4000,d0
+ bcc.w store_max ;exponent out of range
+
+ move.l FPTEMP_LO(a6),d0
+ and.l #$7FFF0000,d0 ;look for all 1's on bits 30-16
+ cmp.l #$7FFF0000,d0
+ beq.b fixlong
+
+ tst.l FPTEMP_LO(a6)
+ bpl.b chklepos
+ cmp.l #$FFFFFFFF,FPTEMP_HI(a6)
+ beq.b fixlong
+ bra.w store_max
+chklepos:
+ tst.l FPTEMP_HI(a6)
+ beq.b fixlong
+ bra.w store_max
+
+operr_word:
+ moveq.l #2,d1 ;write size to d1
+ move.b STAG(a6),d0 ;test stag for nan
+ andi.b #$e0,d0 ;clr all but tag
+ cmpi.b #$60,d0 ;check for nan
+ beq.w operr_nan
+ cmpi.l #$ffff8000,FPTEMP_LO(a6) ;test if ls lword is special
+ bne.b chkwerr ;if not equal, check for incorrect operr
+ bsr check_upper ;check if exp and ms mant are special
+ tst.l d0
+ bne.b chkwerr ;if d0 is true, check for incorrect operr
+ move.l #$80000000,d0 ;store special case result
+ bsr operr_store
+ bra.w not_enabled ;clean and exit
+*
+* CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
+*
+chkwerr:
+ move.w FPTEMP_EX(a6),d0
+ and.w #$7FFF,d0 ;ignore sign bit
+ cmp.w #$3FFE,d0 ;this is the only possible exponent value
+ bne.b store_max
+ move.l FPTEMP_LO(a6),d0
+ swap d0
+ bsr operr_store
+ bra.w not_enabled
+
+operr_byte:
+ moveq.l #1,d1 ;write size to d1
+ move.b STAG(a6),d0 ;test stag for nan
+ andi.b #$e0,d0 ;clr all but tag
+ cmpi.b #$60,d0 ;check for nan
+ beq.b operr_nan
+ cmpi.l #$ffffff80,FPTEMP_LO(a6) ;test if ls lword is special
+ bne.b chkberr ;if not equal, check for incorrect operr
+ bsr check_upper ;check if exp and ms mant are special
+ tst.l d0
+ bne.b chkberr ;if d0 is true, check for incorrect operr
+ move.l #$80000000,d0 ;store special case result
+ bsr operr_store
+ bra.w not_enabled ;clean and exit
+*
+* CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
+*
+chkberr:
+ move.w FPTEMP_EX(a6),d0
+ and.w #$7FFF,d0 ;ignore sign bit
+ cmp.w #$3FFE,d0 ;this is the only possible exponent value
+ bne.b store_max
+ move.l FPTEMP_LO(a6),d0
+ asl.l #8,d0
+ swap d0
+ bsr operr_store
+ bra.w not_enabled
+
+*
+* This operr condition is not of the special case. Set operr
+* and aiop and write the portion of the nan to memory for the
+* given size.
+*
+operr_nan:
+ or.l #opaop_mask,USER_FPSR(a6) ;set operr & aiop
+
+ move.l ETEMP_HI(a6),d0 ;output will be from upper 32 bits
+ bsr operr_store
+ bra end_operr
+*
+* Store_max loads the max pos or negative for the size, sets
+* the operr and aiop bits, and clears inex and ainex, incorrectly
+* set by the 040.
+*
+store_max:
+ or.l #opaop_mask,USER_FPSR(a6) ;set operr & aiop
+ bclr.b #inex2_bit,FPSR_EXCEPT(a6)
+ bclr.b #ainex_bit,FPSR_AEXCEPT(a6)
+ fmove.l #0,FPSR
+
+ tst.w FPTEMP_EX(a6) ;check sign
+ blt.b load_neg
+ move.l #$7fffffff,d0
+ bsr operr_store
+ bra end_operr
+load_neg:
+ move.l #$80000000,d0
+ bsr operr_store
+ bra end_operr
+
+*
+* This routine stores the data in d0, for the given size in d1,
+* to memory or data register as required. A read of the fline
+* is required to determine the destination.
+*
+operr_store:
+ move.l d0,L_SCR1(a6) ;move write data to L_SCR1
+ move.l d1,-(a7) ;save register size
+ bsr.l get_fline ;fline returned in d0
+ move.l (a7)+,d1
+ bftst d0{26:3} ;if mode is zero, dest is Dn
+ bne.b dest_mem
+*
+* Destination is Dn. Get register number from d0. Data is on
+* the stack at (a7). D1 has size: 1=byte,2=word,4=long/single
+*
+ andi.l #7,d0 ;isolate register number
+ cmpi.l #4,d1
+ beq.b op_long ;the most frequent case
+ cmpi.l #2,d1
+ bne.b op_con
+ or.l #8,d0
+ bra.b op_con
+op_long:
+ or.l #$10,d0
+op_con:
+ move.l d0,d1 ;format size:reg for reg_dest
+ bra.l reg_dest ;call to reg_dest returns to caller
+* ;of operr_store
+*
+* Destination is memory. Get <ea> from integer exception frame
+* and call mem_write.
+*
+dest_mem:
+ lea.l L_SCR1(a6),a0 ;put ptr to write data in a0
+ move.l EXC_EA(a6),a1 ;put user destination address in a1
+ move.l d1,d0 ;put size in d0
+ bsr.l mem_write
+ rts
+*
+* Check the exponent for $c000 and the upper 32 bits of the
+* mantissa for $ffffffff. If both are true, return d0 clr
+* and store the lower n bits of the least lword of FPTEMP
+* to d0 for write out. If not, it is a real operr, and set d0.
+*
+check_upper:
+ cmpi.l #$ffffffff,FPTEMP_HI(a6) ;check if first byte is all 1's
+ bne.b true_operr ;if not all 1's then was true operr
+ cmpi.w #$c000,FPTEMP_EX(a6) ;check if incorrectly signalled
+ beq.b not_true_operr ;branch if not true operr
+ cmpi.w #$bfff,FPTEMP_EX(a6) ;check if incorrectly signalled
+ beq.b not_true_operr ;branch if not true operr
+true_operr:
+ move.l #1,d0 ;signal real operr
+ rts
+not_true_operr:
+ clr.l d0 ;signal no real operr
+ rts
+
+*
+* End_operr tests for operr enabled. If not, it cleans up the stack
+* and does an rte. If enabled, it cleans up the stack and branches
+* to the kernel operr handler with only the integer exception
+* frame on the stack and the fpu in the original exceptional state
+* with correct data written to the destination.
+*
+end_operr:
+ btst.b #operr_bit,FPCR_ENABLE(a6)
+ beq.b not_enabled
+enabled:
+ 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_operr
+
+not_enabled:
+*
+* It is possible to have either inex2 or inex1 exceptions with the
+* operr. If the inex enable bit is set in the FPCR, and either
+* inex2 or inex1 occured, 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 operr_exit
+*
+* Inexact enabled and reported, and we must take an inexact exception.
+*
+take_inex:
+ move.b #INEX_VEC,EXC_VEC+1(a6)
+ 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_inex
+*
+* Since operr is only an E1 exception, there is no need to frestore
+* any state back to the fpu.
+*
+operr_exit:
+ movem.l USER_DA(a6),d0-d1/a0-a1
+ fmovem.x USER_FP0(a6),fp0-fp3
+ fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar
+ unlk a6
+ bra.l fpsp_done
+
+ end