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