diff options
Diffstat (limited to 'sys/arch/m68k/fpsp/x_operr.sa')
-rw-r--r-- | sys/arch/m68k/fpsp/x_operr.sa | 381 |
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 |