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