* $NetBSD: x_operr.sa,v 1.6 2024/12/08 06:55:52 andvar 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 erroneously * 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 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 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 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