11.6Sandvar* $NetBSD: x_operr.sa,v 1.6 2024/12/08 06:55:52 andvar Exp $ 21.4Scgd 31.1Smycroft* MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP 41.1Smycroft* M68000 Hi-Performance Microprocessor Division 51.1Smycroft* M68040 Software Package 61.1Smycroft* 71.1Smycroft* M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc. 81.1Smycroft* All rights reserved. 91.1Smycroft* 101.1Smycroft* THE SOFTWARE is provided on an "AS IS" basis and without warranty. 111.1Smycroft* To the maximum extent permitted by applicable law, 121.1Smycroft* MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 131.1Smycroft* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A 141.1Smycroft* PARTICULAR PURPOSE and any warranty against infringement with 151.1Smycroft* regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) 161.1Smycroft* and any accompanying written materials. 171.1Smycroft* 181.1Smycroft* To the maximum extent permitted by applicable law, 191.1Smycroft* IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER 201.1Smycroft* (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS 211.1Smycroft* PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR 221.1Smycroft* OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE 231.1Smycroft* SOFTWARE. Motorola assumes no responsibility for the maintenance 241.1Smycroft* and support of the SOFTWARE. 251.1Smycroft* 261.1Smycroft* You are hereby granted a copyright license to use, modify, and 271.1Smycroft* distribute the SOFTWARE so long as this entire notice is retained 281.1Smycroft* without alteration in any modified and/or redistributed versions, 291.1Smycroft* and that such modified versions are clearly identified as such. 301.1Smycroft* No licenses are granted by implication, estoppel or otherwise 311.1Smycroft* under any patents or trademarks of Motorola, Inc. 321.1Smycroft 331.1Smycroft* 341.1Smycroft* x_operr.sa 3.5 7/1/91 351.1Smycroft* 361.1Smycroft* fpsp_operr --- FPSP handler for operand error exception 371.1Smycroft* 381.1Smycroft* See 68040 User's Manual pp. 9-44f 391.1Smycroft* 401.1Smycroft* Note 1: For trap disabled 040 does the following: 411.1Smycroft* If the dest is a fp reg, then an extended precision non_signaling 421.1Smycroft* NAN is stored in the dest reg. If the dest format is b, w, or l and 431.1Smycroft* the source op is a NAN, then garbage is stored as the result (actually 441.1Smycroft* the upper 32 bits of the mantissa are sent to the integer unit). If 451.1Smycroft* the dest format is integer (b, w, l) and the operr is caused by 461.1Smycroft* integer overflow, or the source op is inf, then the result stored is 471.1Smycroft* garbage. 481.1Smycroft* There are three cases in which operr is incorrectly signaled on the 491.1Smycroft* 040. This occurs for move_out of format b, w, or l for the largest 501.1Smycroft* negative integer (-2^7 for b, -2^15 for w, -2^31 for l). 511.1Smycroft* 521.1Smycroft* On opclass = 011 fmove.(b,w,l) that causes a conversion 531.1Smycroft* overflow -> OPERR, the exponent in wbte (and fpte) is: 541.1Smycroft* byte 56 - (62 - exp) 551.1Smycroft* word 48 - (62 - exp) 561.1Smycroft* long 32 - (62 - exp) 571.1Smycroft* 581.1Smycroft* where exp = (true exp) - 1 591.1Smycroft* 601.6Sandvar* So, wbtemp and fptemp will contain the following on erroneously 611.1Smycroft* signalled operr: 621.1Smycroft* fpts = 1 631.1Smycroft* fpte = $4000 (15 bit externally) 641.1Smycroft* byte fptm = $ffffffff ffffff80 651.1Smycroft* word fptm = $ffffffff ffff8000 661.1Smycroft* long fptm = $ffffffff 80000000 671.1Smycroft* 681.1Smycroft* Note 2: For trap enabled 040 does the following: 691.1Smycroft* If the inst is move_out, then same as Note 1. 701.1Smycroft* If the inst is not move_out, the dest is not modified. 711.1Smycroft* The exceptional operand is not defined for integer overflow 721.1Smycroft* during a move_out. 731.1Smycroft* 741.1Smycroft 751.1SmycroftX_OPERR IDNT 2,1 Motorola 040 Floating Point Software Package 761.1Smycroft 771.1Smycroft section 8 781.1Smycroft 791.1Smycroft include fpsp.h 801.1Smycroft 811.1Smycroft xref mem_write 821.1Smycroft xref real_operr 831.1Smycroft xref real_inex 841.1Smycroft xref get_fline 851.1Smycroft xref fpsp_done 861.1Smycroft xref reg_dest 871.1Smycroft 881.1Smycroft xdef fpsp_operr 891.1Smycroftfpsp_operr: 901.1Smycroft* 911.1Smycroft link a6,#-LOCAL_SIZE 921.1Smycroft fsave -(a7) 931.1Smycroft movem.l d0-d1/a0-a1,USER_DA(a6) 941.1Smycroft fmovem.x fp0-fp3,USER_FP0(a6) 951.1Smycroft fmovem.l fpcr/fpsr/fpiar,USER_FPCR(a6) 961.1Smycroft 971.1Smycroft* 981.1Smycroft* Check if this is an opclass 3 instruction. 991.1Smycroft* If so, fall through, else branch to operr_end 1001.1Smycroft* 1011.1Smycroft btst.b #TFLAG,T_BYTE(a6) 1021.1Smycroft beq.b operr_end 1031.1Smycroft 1041.1Smycroft* 1051.1Smycroft* If the destination size is B,W,or L, the operr must be 1061.1Smycroft* handled here. 1071.1Smycroft* 1081.1Smycroft move.l CMDREG1B(a6),d0 1091.1Smycroft bfextu d0{3:3},d0 ;0=long, 4=word, 6=byte 1101.2Smycroft tst.b d0 ;determine size; check long 1111.1Smycroft beq.w operr_long 1121.1Smycroft cmpi.b #4,d0 ;check word 1131.1Smycroft beq.w operr_word 1141.1Smycroft cmpi.b #6,d0 ;check byte 1151.1Smycroft beq.w operr_byte 1161.1Smycroft 1171.1Smycroft* 1181.1Smycroft* The size is not B,W,or L, so the operr is handled by the 1191.1Smycroft* kernel handler. Set the operr bits and clean up, leaving 1201.1Smycroft* only the integer exception frame on the stack, and the 1211.1Smycroft* fpu in the original exceptional state. 1221.1Smycroft* 1231.1Smycroftoperr_end: 1241.1Smycroft bset.b #operr_bit,FPSR_EXCEPT(a6) 1251.1Smycroft bset.b #aiop_bit,FPSR_AEXCEPT(a6) 1261.1Smycroft 1271.1Smycroft movem.l USER_DA(a6),d0-d1/a0-a1 1281.1Smycroft fmovem.x USER_FP0(a6),fp0-fp3 1291.1Smycroft fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar 1301.1Smycroft frestore (a7)+ 1311.1Smycroft unlk a6 1321.1Smycroft bra.l real_operr 1331.1Smycroft 1341.1Smycroftoperr_long: 1351.1Smycroft moveq.l #4,d1 ;write size to d1 1361.1Smycroft move.b STAG(a6),d0 ;test stag for nan 1371.1Smycroft andi.b #$e0,d0 ;clr all but tag 1381.1Smycroft cmpi.b #$60,d0 ;check for nan 1391.1Smycroft beq operr_nan 1401.1Smycroft cmpi.l #$80000000,FPTEMP_LO(a6) ;test if ls lword is special 1411.1Smycroft bne.b chklerr ;if not equal, check for incorrect operr 1421.1Smycroft bsr check_upper ;check if exp and ms mant are special 1431.1Smycroft tst.l d0 1441.1Smycroft bne.b chklerr ;if d0 is true, check for incorrect operr 1451.1Smycroft move.l #$80000000,d0 ;store special case result 1461.1Smycroft bsr operr_store 1471.1Smycroft bra.w not_enabled ;clean and exit 1481.1Smycroft* 1491.1Smycroft* CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE 1501.1Smycroft* 1511.1Smycroftchklerr: 1521.1Smycroft move.w FPTEMP_EX(a6),d0 1531.1Smycroft and.w #$7FFF,d0 ;ignore sign bit 1541.1Smycroft cmp.w #$3FFE,d0 ;this is the only possible exponent value 1551.1Smycroft bne.b chklerr2 1561.1Smycroftfixlong: 1571.1Smycroft move.l FPTEMP_LO(a6),d0 1581.1Smycroft bsr operr_store 1591.1Smycroft bra.w not_enabled 1601.1Smycroftchklerr2: 1611.1Smycroft move.w FPTEMP_EX(a6),d0 1621.1Smycroft and.w #$7FFF,d0 ;ignore sign bit 1631.1Smycroft cmp.w #$4000,d0 1641.3Smycroft bcc.w store_max ;exponent out of range 1651.1Smycroft 1661.1Smycroft move.l FPTEMP_LO(a6),d0 1671.1Smycroft and.l #$7FFF0000,d0 ;look for all 1's on bits 30-16 1681.1Smycroft cmp.l #$7FFF0000,d0 1691.1Smycroft beq.b fixlong 1701.1Smycroft 1711.1Smycroft tst.l FPTEMP_LO(a6) 1721.1Smycroft bpl.b chklepos 1731.1Smycroft cmp.l #$FFFFFFFF,FPTEMP_HI(a6) 1741.1Smycroft beq.b fixlong 1751.1Smycroft bra.w store_max 1761.1Smycroftchklepos: 1771.1Smycroft tst.l FPTEMP_HI(a6) 1781.1Smycroft beq.b fixlong 1791.1Smycroft bra.w store_max 1801.1Smycroft 1811.1Smycroftoperr_word: 1821.1Smycroft moveq.l #2,d1 ;write size to d1 1831.1Smycroft move.b STAG(a6),d0 ;test stag for nan 1841.1Smycroft andi.b #$e0,d0 ;clr all but tag 1851.1Smycroft cmpi.b #$60,d0 ;check for nan 1861.1Smycroft beq.w operr_nan 1871.1Smycroft cmpi.l #$ffff8000,FPTEMP_LO(a6) ;test if ls lword is special 1881.1Smycroft bne.b chkwerr ;if not equal, check for incorrect operr 1891.1Smycroft bsr check_upper ;check if exp and ms mant are special 1901.1Smycroft tst.l d0 1911.1Smycroft bne.b chkwerr ;if d0 is true, check for incorrect operr 1921.1Smycroft move.l #$80000000,d0 ;store special case result 1931.1Smycroft bsr operr_store 1941.1Smycroft bra.w not_enabled ;clean and exit 1951.1Smycroft* 1961.1Smycroft* CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE 1971.1Smycroft* 1981.1Smycroftchkwerr: 1991.1Smycroft move.w FPTEMP_EX(a6),d0 2001.1Smycroft and.w #$7FFF,d0 ;ignore sign bit 2011.1Smycroft cmp.w #$3FFE,d0 ;this is the only possible exponent value 2021.1Smycroft bne.b store_max 2031.1Smycroft move.l FPTEMP_LO(a6),d0 2041.1Smycroft swap d0 2051.1Smycroft bsr operr_store 2061.1Smycroft bra.w not_enabled 2071.1Smycroft 2081.1Smycroftoperr_byte: 2091.1Smycroft moveq.l #1,d1 ;write size to d1 2101.1Smycroft move.b STAG(a6),d0 ;test stag for nan 2111.1Smycroft andi.b #$e0,d0 ;clr all but tag 2121.1Smycroft cmpi.b #$60,d0 ;check for nan 2131.1Smycroft beq.b operr_nan 2141.1Smycroft cmpi.l #$ffffff80,FPTEMP_LO(a6) ;test if ls lword is special 2151.1Smycroft bne.b chkberr ;if not equal, check for incorrect operr 2161.1Smycroft bsr check_upper ;check if exp and ms mant are special 2171.1Smycroft tst.l d0 2181.1Smycroft bne.b chkberr ;if d0 is true, check for incorrect operr 2191.1Smycroft move.l #$80000000,d0 ;store special case result 2201.1Smycroft bsr operr_store 2211.1Smycroft bra.w not_enabled ;clean and exit 2221.1Smycroft* 2231.1Smycroft* CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE 2241.1Smycroft* 2251.1Smycroftchkberr: 2261.1Smycroft move.w FPTEMP_EX(a6),d0 2271.1Smycroft and.w #$7FFF,d0 ;ignore sign bit 2281.1Smycroft cmp.w #$3FFE,d0 ;this is the only possible exponent value 2291.1Smycroft bne.b store_max 2301.1Smycroft move.l FPTEMP_LO(a6),d0 2311.1Smycroft asl.l #8,d0 2321.1Smycroft swap d0 2331.1Smycroft bsr operr_store 2341.1Smycroft bra.w not_enabled 2351.1Smycroft 2361.1Smycroft* 2371.1Smycroft* This operr condition is not of the special case. Set operr 2381.1Smycroft* and aiop and write the portion of the nan to memory for the 2391.1Smycroft* given size. 2401.1Smycroft* 2411.1Smycroftoperr_nan: 2421.1Smycroft or.l #opaop_mask,USER_FPSR(a6) ;set operr & aiop 2431.1Smycroft 2441.1Smycroft move.l ETEMP_HI(a6),d0 ;output will be from upper 32 bits 2451.1Smycroft bsr operr_store 2461.1Smycroft bra end_operr 2471.1Smycroft* 2481.1Smycroft* Store_max loads the max pos or negative for the size, sets 2491.1Smycroft* the operr and aiop bits, and clears inex and ainex, incorrectly 2501.1Smycroft* set by the 040. 2511.1Smycroft* 2521.1Smycroftstore_max: 2531.1Smycroft or.l #opaop_mask,USER_FPSR(a6) ;set operr & aiop 2541.1Smycroft bclr.b #inex2_bit,FPSR_EXCEPT(a6) 2551.1Smycroft bclr.b #ainex_bit,FPSR_AEXCEPT(a6) 2561.1Smycroft fmove.l #0,FPSR 2571.1Smycroft 2581.1Smycroft tst.w FPTEMP_EX(a6) ;check sign 2591.1Smycroft blt.b load_neg 2601.1Smycroft move.l #$7fffffff,d0 2611.1Smycroft bsr operr_store 2621.1Smycroft bra end_operr 2631.1Smycroftload_neg: 2641.1Smycroft move.l #$80000000,d0 2651.1Smycroft bsr operr_store 2661.1Smycroft bra end_operr 2671.1Smycroft 2681.1Smycroft* 2691.1Smycroft* This routine stores the data in d0, for the given size in d1, 2701.1Smycroft* to memory or data register as required. A read of the fline 2711.1Smycroft* is required to determine the destination. 2721.1Smycroft* 2731.1Smycroftoperr_store: 2741.1Smycroft move.l d0,L_SCR1(a6) ;move write data to L_SCR1 2751.1Smycroft move.l d1,-(a7) ;save register size 2761.1Smycroft bsr.l get_fline ;fline returned in d0 2771.1Smycroft move.l (a7)+,d1 2781.1Smycroft bftst d0{26:3} ;if mode is zero, dest is Dn 2791.1Smycroft bne.b dest_mem 2801.1Smycroft* 2811.1Smycroft* Destination is Dn. Get register number from d0. Data is on 2821.1Smycroft* the stack at (a7). D1 has size: 1=byte,2=word,4=long/single 2831.1Smycroft* 2841.1Smycroft andi.l #7,d0 ;isolate register number 2851.1Smycroft cmpi.l #4,d1 2861.1Smycroft beq.b op_long ;the most frequent case 2871.1Smycroft cmpi.l #2,d1 2881.1Smycroft bne.b op_con 2891.1Smycroft or.l #8,d0 2901.1Smycroft bra.b op_con 2911.1Smycroftop_long: 2921.1Smycroft or.l #$10,d0 2931.1Smycroftop_con: 2941.1Smycroft move.l d0,d1 ;format size:reg for reg_dest 2951.1Smycroft bra.l reg_dest ;call to reg_dest returns to caller 2961.1Smycroft* ;of operr_store 2971.1Smycroft* 2981.1Smycroft* Destination is memory. Get <ea> from integer exception frame 2991.1Smycroft* and call mem_write. 3001.1Smycroft* 3011.1Smycroftdest_mem: 3021.1Smycroft lea.l L_SCR1(a6),a0 ;put ptr to write data in a0 3031.1Smycroft move.l EXC_EA(a6),a1 ;put user destination address in a1 3041.1Smycroft move.l d1,d0 ;put size in d0 3051.1Smycroft bsr.l mem_write 3061.1Smycroft rts 3071.1Smycroft* 3081.1Smycroft* Check the exponent for $c000 and the upper 32 bits of the 3091.1Smycroft* mantissa for $ffffffff. If both are true, return d0 clr 3101.1Smycroft* and store the lower n bits of the least lword of FPTEMP 3111.1Smycroft* to d0 for write out. If not, it is a real operr, and set d0. 3121.1Smycroft* 3131.1Smycroftcheck_upper: 3141.1Smycroft cmpi.l #$ffffffff,FPTEMP_HI(a6) ;check if first byte is all 1's 3151.1Smycroft bne.b true_operr ;if not all 1's then was true operr 3161.1Smycroft cmpi.w #$c000,FPTEMP_EX(a6) ;check if incorrectly signalled 3171.1Smycroft beq.b not_true_operr ;branch if not true operr 3181.1Smycroft cmpi.w #$bfff,FPTEMP_EX(a6) ;check if incorrectly signalled 3191.1Smycroft beq.b not_true_operr ;branch if not true operr 3201.1Smycrofttrue_operr: 3211.1Smycroft move.l #1,d0 ;signal real operr 3221.1Smycroft rts 3231.1Smycroftnot_true_operr: 3241.1Smycroft clr.l d0 ;signal no real operr 3251.1Smycroft rts 3261.1Smycroft 3271.1Smycroft* 3281.1Smycroft* End_operr tests for operr enabled. If not, it cleans up the stack 3291.1Smycroft* and does an rte. If enabled, it cleans up the stack and branches 3301.1Smycroft* to the kernel operr handler with only the integer exception 3311.1Smycroft* frame on the stack and the fpu in the original exceptional state 3321.1Smycroft* with correct data written to the destination. 3331.1Smycroft* 3341.1Smycroftend_operr: 3351.1Smycroft btst.b #operr_bit,FPCR_ENABLE(a6) 3361.1Smycroft beq.b not_enabled 3371.1Smycroftenabled: 3381.1Smycroft movem.l USER_DA(a6),d0-d1/a0-a1 3391.1Smycroft fmovem.x USER_FP0(a6),fp0-fp3 3401.1Smycroft fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar 3411.1Smycroft frestore (a7)+ 3421.1Smycroft unlk a6 3431.1Smycroft bra.l real_operr 3441.1Smycroft 3451.1Smycroftnot_enabled: 3461.1Smycroft* 3471.1Smycroft* It is possible to have either inex2 or inex1 exceptions with the 3481.1Smycroft* operr. If the inex enable bit is set in the FPCR, and either 3491.5Swiz* inex2 or inex1 occurred, we must clean up and branch to the 3501.1Smycroft* real inex handler. 3511.1Smycroft* 3521.1Smycroftck_inex: 3531.1Smycroft move.b FPCR_ENABLE(a6),d0 3541.1Smycroft and.b FPSR_EXCEPT(a6),d0 3551.1Smycroft andi.b #$3,d0 3561.1Smycroft beq.w operr_exit 3571.1Smycroft* 3581.1Smycroft* Inexact enabled and reported, and we must take an inexact exception. 3591.1Smycroft* 3601.1Smycrofttake_inex: 3611.1Smycroft move.b #INEX_VEC,EXC_VEC+1(a6) 3621.1Smycroft move.l USER_FPSR(a6),FPSR_SHADOW(a6) 3631.1Smycroft or.l #sx_mask,E_BYTE(a6) 3641.1Smycroft movem.l USER_DA(a6),d0-d1/a0-a1 3651.1Smycroft fmovem.x USER_FP0(a6),fp0-fp3 3661.1Smycroft fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar 3671.1Smycroft frestore (a7)+ 3681.1Smycroft unlk a6 3691.1Smycroft bra.l real_inex 3701.1Smycroft* 3711.1Smycroft* Since operr is only an E1 exception, there is no need to frestore 3721.1Smycroft* any state back to the fpu. 3731.1Smycroft* 3741.1Smycroftoperr_exit: 3751.1Smycroft movem.l USER_DA(a6),d0-d1/a0-a1 3761.1Smycroft fmovem.x USER_FP0(a6),fp0-fp3 3771.1Smycroft fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar 3781.1Smycroft unlk a6 3791.1Smycroft bra.l fpsp_done 3801.1Smycroft 3811.1Smycroft end 382