[BACK]Return to gen_except.sa CVS log [TXT][DIR] Up to [local] / sys / arch / m68k / fpsp

File: [local] / sys / arch / m68k / fpsp / gen_except.sa (download)

Revision 1.1, Tue Mar 4 16:07:06 2008 UTC (16 years, 2 months ago) by nbrk
Branch point for: MAIN

Initial revision

*	$OpenBSD: gen_except.sa,v 1.2 1996/05/29 21:05:29 niklas Exp $
*	$NetBSD: gen_except.sa,v 1.3 1994/10/26 07:49:07 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.

*
*	gen_except.sa 3.7 1/16/92
*
*	gen_except --- FPSP routine to detect reportable exceptions
*	
*	This routine compares the exception enable byte of the
*	user_fpcr on the stack with the exception status byte
*	of the user_fpsr. 
*
*	Any routine which may report an exceptions must load
*	the stack frame in memory with the exceptional operand(s).
*
*	Priority for exceptions is:
*
*	Highest:	bsun
*			snan
*			operr
*			ovfl
*			unfl
*			dz
*			inex2
*	Lowest:		inex1
*
*	Note: The IEEE standard specifies that inex2 is to be
*	reported if ovfl occurs and the ovfl enable bit is not
*	set but the inex2 enable bit is.  
*

GEN_EXCEPT    IDNT    2,1 Motorola 040 Floating Point Software Package

	section 8

	include fpsp.h

	xref	real_trace
	xref	fpsp_done
	xref	fpsp_fmt_error

exc_tbl:
	dc.l	bsun_exc
	dc.l	commonE1
	dc.l	commonE1
	dc.l	ovfl_unfl
	dc.l	ovfl_unfl
	dc.l	commonE1
	dc.l	commonE3
	dc.l	commonE3
	dc.l	no_match

	xdef	gen_except
gen_except:
	cmpi.b	#IDLE_SIZE-4,1(a7)	;test for idle frame
	beq.w	do_check		;go handle idle frame
	cmpi.b	#UNIMP_40_SIZE-4,1(a7)	;test for orig unimp frame
	beq.b	unimp_x			;go handle unimp frame
	cmpi.b	#UNIMP_41_SIZE-4,1(a7)	;test for rev unimp frame
	beq.b	unimp_x			;go handle unimp frame
	cmpi.b	#BUSY_SIZE-4,1(a7)	;if size <> $60, fmt error
	bne.l	fpsp_fmt_error
	lea.l	BUSY_SIZE+LOCAL_SIZE(a7),a1 ;init a1 so fpsp.h
*					;equates will work
* Fix up the new busy frame with entries from the unimp frame
*
	move.l	ETEMP_EX(a6),ETEMP_EX(a1) ;copy etemp from unimp
	move.l	ETEMP_HI(a6),ETEMP_HI(a1) ;frame to busy frame
	move.l	ETEMP_LO(a6),ETEMP_LO(a1) 
	move.l	CMDREG1B(a6),CMDREG1B(a1) ;set inst in frame to unimp
	move.l	CMDREG1B(a6),d0		;fix cmd1b to make it
	and.l	#$03c30000,d0		;work for cmd3b
	bfextu	CMDREG1B(a6){13:1},d1	;extract bit 2
	lsl.l	#5,d1			
	swap	d1
	or.l	d1,d0			;put it in the right place
	bfextu	CMDREG1B(a6){10:3},d1	;extract bit 3,4,5
	lsl.l	#2,d1
	swap	d1
	or.l	d1,d0			;put them in the right place
	move.l	d0,CMDREG3B(a1)		;in the busy frame
*
* Or in the FPSR from the emulation with the USER_FPSR on the stack.
*
	fmove.l	FPSR,d0		
	or.l	d0,USER_FPSR(a6)
	move.l	USER_FPSR(a6),FPSR_SHADOW(a1) ;set exc bits
	or.l	#sx_mask,E_BYTE(a1)
	bra	do_clean

*
* Frame is an unimp frame possible resulting from an fmove <ea>,fp0
* that caused an exception
*
* a1 is modified to point into the new frame allowing fpsp equates
* to be valid.
*
unimp_x:
	cmpi.b	#UNIMP_40_SIZE-4,1(a7)	;test for orig unimp frame
	bne.b	test_rev
	lea.l	UNIMP_40_SIZE+LOCAL_SIZE(a7),a1
	bra.b	unimp_con
test_rev:
	cmpi.b	#UNIMP_41_SIZE-4,1(a7)	;test for rev unimp frame
	bne.l	fpsp_fmt_error		;if not $28 or $30
	lea.l	UNIMP_41_SIZE+LOCAL_SIZE(a7),a1
	
unimp_con:
*
* Fix up the new unimp frame with entries from the old unimp frame
*
	move.l	CMDREG1B(a6),CMDREG1B(a1) ;set inst in frame to unimp
*
* Or in the FPSR from the emulation with the USER_FPSR on the stack.
*
	fmove.l	FPSR,d0		
	or.l	d0,USER_FPSR(a6)
	bra	do_clean

*
* Frame is idle, so check for exceptions reported through
* USER_FPSR and set the unimp frame accordingly.  
* A7 must be incremented to the point before the
* idle fsave vector to the unimp vector.
*
	
do_check:
	add.l	#4,A7			;point A7 back to unimp frame
*
* Or in the FPSR from the emulation with the USER_FPSR on the stack.
*
	fmove.l	FPSR,d0		
	or.l	d0,USER_FPSR(a6)
*
* On a busy frame, we must clear the nmnexc bits.
*
	cmpi.b	#BUSY_SIZE-4,1(a7)	;check frame type
	bne.b	check_fr		;if busy, clr nmnexc
	clr.w	NMNEXC(a6)		;clr nmnexc & nmcexc
	btst.b	#5,CMDREG1B(a6)		;test for fmove out
	bne.b	frame_com
	move.l	USER_FPSR(a6),FPSR_SHADOW(a6) ;set exc bits
	or.l	#sx_mask,E_BYTE(a6)
	bra.b	frame_com
check_fr:
	cmp.b	#UNIMP_40_SIZE-4,1(a7)
	beq.b	frame_com
	clr.w	NMNEXC(a6)
frame_com:
	move.b	FPCR_ENABLE(a6),d0	;get fpcr enable byte
	and.b	FPSR_EXCEPT(a6),d0	;and in the fpsr exc byte
	bfffo	d0{24:8},d1		;test for first set bit
	lea.l	exc_tbl,a0		;load jmp table address
	subi.b	#24,d1			;normalize bit offset to 0-8
	move.l	(a0,d1.w*4),a0		;load routine address based
*					;based on first enabled exc
	jmp	(a0)			;jump to routine
*
* Bsun is not possible in unimp or unsupp
*
bsun_exc:
	bra	do_clean
*
* The typical work to be done to the unimp frame to report an 
* exception is to set the E1/E3 byte and clr the U flag.
* commonE1 does this for E1 exceptions, which are snan, 
* operr, and dz.  commonE3 does this for E3 exceptions, which 
* are inex2 and inex1, and also clears the E1 exception bit
* left over from the unimp exception.
*
commonE1:
	bset.b	#E1,E_BYTE(a6)		;set E1 flag
	bra.w	commonE			;go clean and exit

commonE3:
	tst.b	UFLG_TMP(a6)		;test flag for unsup/unimp state
	bne.b	unsE3
uniE3:
	bset.b	#E3,E_BYTE(a6)		;set E3 flag
	bclr.b	#E1,E_BYTE(a6)		;clr E1 from unimp
	bra.w	commonE

unsE3:
	tst.b	RES_FLG(a6)
	bne.b	unsE3_0	
unsE3_1:
	bset.b	#E3,E_BYTE(a6)		;set E3 flag
unsE3_0:
	bclr.b	#E1,E_BYTE(a6)		;clr E1 flag
	move.l	CMDREG1B(a6),d0
	and.l	#$03c30000,d0		;work for cmd3b
	bfextu	CMDREG1B(a6){13:1},d1	;extract bit 2
	lsl.l	#5,d1			
	swap	d1
	or.l	d1,d0			;put it in the right place
	bfextu	CMDREG1B(a6){10:3},d1	;extract bit 3,4,5
	lsl.l	#2,d1
	swap	d1
	or.l	d1,d0			;put them in the right place
	move.l	d0,CMDREG3B(a6)		;in the busy frame

commonE:
	bclr.b	#UFLAG,T_BYTE(a6)	;clr U flag from unimp
	bra.w	do_clean		;go clean and exit
*
* No bits in the enable byte match existing exceptions.  Check for
* the case of the ovfl exc without the ovfl enabled, but with
* inex2 enabled.
*
no_match:
	btst.b	#inex2_bit,FPCR_ENABLE(a6) ;check for ovfl/inex2 case
	beq.b	no_exc			;if clear, exit
	btst.b	#ovfl_bit,FPSR_EXCEPT(a6) ;now check ovfl
	beq.b	no_exc			;if clear, exit
	bra.b	ovfl_unfl		;go to unfl_ovfl to determine if
*					;it is an unsupp or unimp exc
	
* No exceptions are to be reported.  If the instruction was 
* unimplemented, no FPU restore is necessary.  If it was
* unsupported, we must perform the restore.
no_exc:
	tst.b	UFLG_TMP(a6)	;test flag for unsupp/unimp state
	beq.b	uni_no_exc
uns_no_exc:
	tst.b	RES_FLG(a6)	;check if frestore is needed
	bne.w	do_clean 	;if clear, no frestore needed
uni_no_exc:
	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	finish_up
*
* Unsupported Data Type Handler:
* Ovfl:
*   An fmoveout that results in an overflow is reported this way.
* Unfl:
*   An fmoveout that results in an underflow is reported this way.
*
* Unimplemented Instruction Handler:
* Ovfl:
*   Only scosh, setox, ssinh, stwotox, and scale can set overflow in 
*   this manner.
* Unfl:
*   Stwotox, setox, and scale can set underflow in this manner.
*   Any of the other Library Routines such that f(x)=x in which
*   x is an extended denorm can report an underflow exception. 
*   It is the responsibility of the exception-causing exception 
*   to make sure that WBTEMP is correct.
*
*   The exceptional operand is in FP_SCR1.
*
ovfl_unfl:
	tst.b	UFLG_TMP(a6)	;test flag for unsupp/unimp state
	beq.b	ofuf_con
*
* The caller was from an unsupported data type trap.  Test if the
* caller set CU_ONLY.  If so, the exceptional operand is expected in
* FPTEMP, rather than WBTEMP.
*
	tst.b	CU_ONLY(a6)		;test if inst is cu-only
	beq.w	unsE3
*	move.w	#$fe,CU_SAVEPC(a6)
	clr.b	CU_SAVEPC(a6)
	bset.b	#E1,E_BYTE(a6)		;set E1 exception flag
	move.w	ETEMP_EX(a6),FPTEMP_EX(a6)
	move.l	ETEMP_HI(a6),FPTEMP_HI(a6)
	move.l	ETEMP_LO(a6),FPTEMP_LO(a6)
	bset.b	#fptemp15_bit,DTAG(a6)	;set fpte15
	bclr.b	#UFLAG,T_BYTE(a6)	;clr U flag from unimp
	bra.w	do_clean		;go clean and exit

ofuf_con:
	move.b	(a7),VER_TMP(a6)	;save version number
	cmpi.b	#BUSY_SIZE-4,1(a7)	;check for busy frame
	beq.b	busy_fr			;if unimp, grow to busy
	cmpi.b	#VER_40,(a7)		;test for orig unimp frame
	bne.b	try_41			;if not, test for rev frame
	moveq.l	#13,d0			;need to zero 14 lwords
	bra.b	ofuf_fin
try_41:
	cmpi.b	#VER_41,(a7)		;test for rev unimp frame
	bne.l	fpsp_fmt_error		;if neither, exit with error
	moveq.l	#11,d0			;need to zero 12 lwords

ofuf_fin:
	clr.l	(a7)
loop1:
	clr.l	-(a7)			;clear and dec a7
	dbra.w	d0,loop1
	move.b	VER_TMP(a6),(a7)
	move.b	#BUSY_SIZE-4,1(a7)		;write busy fmt word.
busy_fr:
	move.l	FP_SCR1(a6),WBTEMP_EX(a6)	;write
	move.l	FP_SCR1+4(a6),WBTEMP_HI(a6)	;execptional op to
	move.l	FP_SCR1+8(a6),WBTEMP_LO(a6)	;wbtemp
	bset.b	#E3,E_BYTE(a6)			;set E3 flag
	bclr.b	#E1,E_BYTE(a6)			;make sure E1 is clear
	bclr.b	#UFLAG,T_BYTE(a6)		;clr U flag
	move.l	USER_FPSR(a6),FPSR_SHADOW(a6)
	or.l	#sx_mask,E_BYTE(a6)
	move.l	CMDREG1B(a6),d0		;fix cmd1b to make it
	and.l	#$03c30000,d0		;work for cmd3b
	bfextu	CMDREG1B(a6){13:1},d1	;extract bit 2
	lsl.l	#5,d1			
	swap	d1
	or.l	d1,d0			;put it in the right place
	bfextu	CMDREG1B(a6){10:3},d1	;extract bit 3,4,5
	lsl.l	#2,d1
	swap	d1
	or.l	d1,d0			;put them in the right place
	move.l	d0,CMDREG3B(a6)		;in the busy frame

*
* Check if the frame to be restored is busy or unimp.
*** NOTE *** Bug fix for errata (0d43b #3)
* If the frame is unimp, we must create a busy frame to 
* fix the bug with the nmnexc bits in cases in which they
* are set by a previous instruction and not cleared by
* the save. The frame will be unimp only if the final 
* instruction in an emulation routine caused the exception
* by doing an fmove <ea>,fp0.  The exception operand, in
* internal format, is in fptemp.
*
do_clean:
	cmpi.b	#UNIMP_40_SIZE-4,1(a7)
	bne.b	do_con
	moveq.l	#13,d0			;in orig, need to zero 14 lwords
	bra.b	do_build
do_con:
	cmpi.b	#UNIMP_41_SIZE-4,1(a7)
	bne.b	do_restore		;frame must be busy
	moveq.l	#11,d0			;in rev, need to zero 12 lwords

do_build:
	move.b	(a7),VER_TMP(a6)
	clr.l	(a7)
loop2:
	clr.l	-(a7)			;clear and dec a7
	dbra.w	d0,loop2
*
* Use a1 as pointer into new frame.  a6 is not correct if an unimp or
* busy frame was created as the result of an exception on the final
* instruction of an emulation routine.
*
* We need to set the nmcexc bits if the exception is E1. Otherwise,
* the exc taken will be inex2.
*
	lea.l	BUSY_SIZE+LOCAL_SIZE(a7),a1	;init a1 for new frame
	move.b	VER_TMP(a6),(a7)	;write busy fmt word
	move.b	#BUSY_SIZE-4,1(a7)
	move.l	FP_SCR1(a6),WBTEMP_EX(a1) 	;write
	move.l	FP_SCR1+4(a6),WBTEMP_HI(a1)	;exceptional op to
	move.l	FP_SCR1+8(a6),WBTEMP_LO(a1)	;wbtemp
*	btst.b	#E1,E_BYTE(a1)
*	beq.b	do_restore
	bfextu	USER_FPSR(a6){17:4},d0	;get snan/operr/ovfl/unfl bits
	bfins	d0,NMCEXC(a1){4:4}	;and insert them in nmcexc
	move.l	USER_FPSR(a6),FPSR_SHADOW(a1) ;set exc bits
	or.l	#sx_mask,E_BYTE(a1)
	
do_restore:
	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)+
	tst.b	RES_FLG(a6)	;RES_FLG indicates a "continuation" frame
	beq	cont
	bsr	bug1384
cont:
	unlk	a6
*
* If trace mode enabled, then go to trace handler.  This handler 
* cannot have any fp instructions.  If there are fp inst's and an 
* exception has been restored into the machine then the exception 
* will occur upon execution of the fp inst.  This is not desirable 
* in the kernel (supervisor mode).  See MC68040 manual Section 9.3.8.
*
finish_up:
	btst.b	#7,(a7)		;test T1 in SR
	bne.b	g_trace
	btst.b	#6,(a7)		;test T0 in SR
	bne.b	g_trace
	bra.l	fpsp_done
*
* Change integer stack to look like trace stack
* The address of the instruction that caused the
* exception is already in the integer stack (is
* the same as the saved friar)
*
* If the current frame is already a 6-word stack then all
* that needs to be done is to change the vector# to TRACE.
* If the frame is only a 4-word stack (meaning we got here
* on an Unsupported data type exception), then we need to grow
* the stack an extra 2 words and get the FPIAR from the FPU.
*
g_trace:
	bftst	EXC_VEC-4(sp){0:4}
	bne	g_easy

	subq.l	#4,sp		make room
	move.l	4(sp),(sp)
	move.l	8(sp),4(sp)
	sub.l	#BUSY_SIZE,sp
	fsave	(sp)
	fmove.l	fpiar,BUSY_SIZE+EXC_EA-4(sp)
	frestore (sp)
	add.l	#BUSY_SIZE,sp

g_easy:
	move.w	#TRACE_VEC,EXC_VEC-4(a7)
	bra.l	real_trace
*
*  This is a work-around for hardware bug 1384.
*
bug1384:
	link	a5,#0
	fsave	-(sp)
	cmpi.b	#$41,(sp)	; check for correct frame
	beq	frame_41
	bgt	nofix		; if more advanced mask, do nada

frame_40:
	tst.b	1(sp)		; check to see if idle
	bne	notidle
idle40:
	clr.l	(sp)		; get rid of old fsave frame
        move.l  d1,USER_D1(a6)  ; save d1
	move.w	#8,d1		; place unimp frame instead
loop40:	clr.l	-(sp)
	dbra	d1,loop40
        move.l  USER_D1(a6),d1  ; restore d1
	move.l	#$40280000,-(sp)
	frestore (sp)+
	unlk  	a5	
	rts

frame_41:
	tst.b	1(sp)		; check to see if idle
	bne	notidle	
idle41:
	clr.l	(sp)		; get rid of old fsave frame
        move.l  d1,USER_D1(a6)  ; save d1
	move.w	#10,d1		; place unimp frame instead
loop41:	clr.l	-(sp)
	dbra	d1,loop41
        move.l  USER_D1(a6),d1  ; restore d1
	move.l	#$41300000,-(sp)
	frestore (sp)+
	unlk	a5	
	rts

notidle:
	bclr.b	#etemp15_bit,-40(a5) 
	frestore (sp)+
	unlk	a5	
	rts

nofix:
	frestore (sp)+
	unlk	a5	
	rts

	end