patch-1.3.94 linux/arch/m68k/fpsp040/skeleton.S

Next file: linux/arch/m68k/fpsp040/slog2.S
Previous file: linux/arch/m68k/fpsp040/sint.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S
@@ -0,0 +1,568 @@
+|
+|	skeleton.sa 3.2 4/26/91
+|
+|	This file contains code that is system dependent and will
+|	need to be modified to install the FPSP.
+|
+|	Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'.
+|	Put any target system specific handling that must be done immediately
+|	before the jump instruction.  If there no handling necessary, then
+|	the 'fpsp_xxxx' handler entry point should be placed in the exception
+|	table so that the 'jmp' can be eliminated. If the FPSP determines that the
+|	exception is one that must be reported then there will be a
+|	return from the package by a 'jmp real_xxxx'.  At that point
+|	the machine state will be identical to the state before
+|	the FPSP was entered.  In particular, whatever condition
+|	that caused the exception will still be pending when the FPSP
+|	package returns.  Thus, there will be system specific code
+|	to handle the exception.
+|
+|	If the exception was completely handled by the package, then
+|	the return will be via a 'jmp fpsp_done'.  Unless there is 
+|	OS specific work to be done (such as handling a context switch or
+|	interrupt) the user program can be resumed via 'rte'.
+|
+|	In the following skeleton code, some typical 'real_xxxx' handling
+|	code is shown.  This code may need to be moved to an appropriate
+|	place in the target system, or rewritten.
+|	
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|
+|	Modified for Linux-1.3.x by Jes Sorensen (jds@kom.auc.dk)
+|
+
+#include <linux/linkage.h>
+
+|SKELETON	idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section 15
+|
+|	The following counters are used for standalone testing
+|
+sigunimp:	.long	0
+sigbsun:		.long	0
+siginex:		.long	0
+sigdz:		.long	0
+sigunfl:		.long	0
+sigovfl:		.long	0
+sigoperr:	.long	0
+sigsnan:		.long	0
+sigunsupp:	.long	0
+
+	|section 8
+ 
+	.include "fpsp.h"
+
+LOFF_ORIG_D0	= 0x20
+
+#define SAVE_ALL				\
+	clrl	%sp@-;     /* stk_adj */	\
+	movel	%d0,%sp@-; /* orig d0 */	\
+	movel	%d0,%sp@-; /* d0 */		\
+	moveml	%d1-%d5/%a0-%a1,%sp@-
+
+	|xref	b1238_fix
+
+|
+|	Divide by Zero exception
+|
+|	All dz exceptions are 'real', hence no fpsp_dz entry point.
+|
+	.global	dz
+	.global	real_dz
+dz:
+real_dz:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl	#1,sigdz		|for standalone testing
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	Inexact exception
+|
+|	All inexact exceptions are real, but the 'real' handler
+|	will probably want to clear the pending exception.
+|	The provided code will clear the E3 exception (if pending), 
+|	otherwise clear the E1 exception.  The frestore is not really
+|	necessary for E1 exceptions.
+|
+| Code following the 'inex' label is to handle bug #1232.  In this
+| bug, if an E1 snan, ovfl, or unfl occured, and the process was
+| swapped out before taking the exception, the exception taken on
+| return was inex, rather than the correct exception.  The snan, ovfl,
+| and unfl exception to be taken must not have been enabled.  The
+| fix is to check for E1, and the existence of one of snan, ovfl,
+| or unfl bits set in the fpsr.  If any of these are set, branch
+| to the appropriate  handler for the exception in the fpsr.  Note
+| that this fix is only for d43b parts, and is skipped if the
+| version number is not $40.
+| 
+|
+	.global	real_inex
+	.global	inex
+inex:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	cmpib		#VER_40,(%sp)		|test version number
+	bnes		not_fmt40
+	fmovel		%fpsr,-(%sp)
+	btstb		#E1,E_BYTE(%a6)		|test for E1 set
+	beqs		not_b1232
+	btstb		#snan_bit,2(%sp) |test for snan
+	beq		inex_ckofl
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+	bra		snan
+inex_ckofl:
+	btstb		#ovfl_bit,2(%sp) |test for ovfl
+	beq		inex_ckufl 
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+	bra		ovfl
+inex_ckufl:
+	btstb		#unfl_bit,2(%sp) |test for unfl
+	beq		not_b1232
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+	bra		unfl
+
+|
+| We do not have the bug 1232 case.  Clean up the stack and call
+| real_inex.
+|
+not_b1232:
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+
+real_inex:
+
+	addl		#1,siginex		|for standalone testing
+
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+not_fmt40:
+	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
+	beqs		inex_cke1
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+	moveml		%d0/%d1,USER_DA(%a6)
+	bfextu		CMDREG1B(%a6){#6:#3},%d0		|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix		|test for bug1238 case
+	moveml		USER_DA(%a6),%d0/%d1
+	bras		inex_done
+inex_cke1:
+	bclrb		#E1,E_BYTE(%a6)
+inex_done:
+	frestore	(%sp)+
+	unlk		%a6
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Overflow exception
+|
+	|xref	fpsp_ovfl
+	.global	real_ovfl
+	.global	ovfl
+ovfl:
+	jmp	fpsp_ovfl
+real_ovfl:
+
+	addl		#1,sigovfl		|for standalone testing
+
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
+	bnes		ovfl_done
+	bclrb		#E1,E_BYTE(%a6)
+ovfl_done:
+	frestore	(%sp)+
+	unlk		%a6
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Underflow exception
+|
+	|xref	fpsp_unfl
+	.global	real_unfl
+	.global	unfl
+unfl:
+	jmp	fpsp_unfl
+real_unfl:
+
+	addl		#1,sigunfl		|for standalone testing
+
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
+	bnes		unfl_done
+	bclrb		#E1,E_BYTE(%a6)
+unfl_done:
+	frestore	(%sp)+
+	unlk		%a6
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Signalling NAN exception
+|
+	|xref	fpsp_snan
+	.global	real_snan
+	.global	snan
+snan:
+	jmp	fpsp_snan
+real_snan:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|snan is always an E1 exception
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigsnan		|for standalone testing
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Operand Error exception
+|
+	|xref	fpsp_operr
+	.global	real_operr
+	.global	operr
+operr:
+	jmp	fpsp_operr
+real_operr:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|operr is always an E1 exception
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigoperr		|for standalone testing
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+	
+|
+|	BSUN exception
+|
+|	This sample handler simply clears the nan bit in the FPSR.
+|
+	|xref	fpsp_bsun
+	.global	real_bsun
+	.global	bsun
+bsun:
+	jmp	fpsp_bsun
+real_bsun:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|bsun is always an E1 exception
+	fmovel		%FPSR,-(%sp)
+	bclrb		#nan_bit,(%sp)
+	fmovel		(%sp)+,%FPSR
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigbsun		|for standalone testing
+
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	F-line exception
+|
+|	A 'real' F-line exception is one that the FPSP isn't supposed to 
+|	handle. E.g. an instruction with a co-processor ID that is not 1.
+|
+|
+	|xref	fpsp_fline
+	.global	real_fline
+	.global	fline
+fline:
+	jmp	fpsp_fline
+real_fline:
+
+	addl		#1,sigunimp		|for standalone testing
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	Unsupported data type exception
+|
+	|xref	fpsp_unsupp
+	.global	real_unsupp
+	.global	unsupp
+unsupp:
+	jmp	fpsp_unsupp
+real_unsupp:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|unsupp is always an E1 exception
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigunsupp		|for standalone testing
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	Trace exception
+|
+	.global	real_trace
+real_trace:
+	|
+	bral	SYMBOL_NAME(trap)
+
+|
+|	fpsp_fmt_error --- exit point for frame format error
+|
+|	The fpu stack frame does not match the frames existing
+|	or planned at the time of this writing.  The fpsp is
+|	unable to handle frame sizes not in the following
+|	version:size pairs:
+|
+|	{4060, 4160} - busy frame
+|	{4028, 4130} - unimp frame
+|	{4000, 4100} - idle frame
+|
+|	This entry point simply holds an f-line illegal value.  
+|	Replace this with a call to your kernel panic code or
+|	code to handle future revisions of the fpu.
+|
+	.global	fpsp_fmt_error
+fpsp_fmt_error:
+
+	.long	0xf27f0000	|f-line illegal 
+
+|
+|	fpsp_done --- FPSP exit point
+|
+|	The exception has been handled by the package and we are ready
+|	to return to user mode, but there may be OS specific code
+|	to execute before we do.  If there is, do it now.
+|
+|
+
+	.global	fpsp_done
+fpsp_done:
+	btst	#0x5,%sp@		| supervisor bit set in saved SR?
+	beq	Lnotkern
+	rte
+Lnotkern:
+	tstl	SYMBOL_NAME(need_resched)
+	bne	Lmustsched
+	rte
+Lmustsched:
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
+	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
+	
+
+|
+|	mem_write --- write to user or supervisor address space
+|
+| Writes to memory while in supervisor mode.  copyout accomplishes
+| this via a 'moves' instruction.  copyout is a UNIX SVR3 (and later) function.
+| If you don't have copyout, use the local copy of the function below.
+|
+|	a0 - supervisor source address
+|	a1 - user destination address
+|	d0 - number of bytes to write (maximum count is 12)
+|
+| The supervisor source address is guaranteed to point into the supervisor
+| stack.  The result is that a UNIX
+| process is allowed to sleep as a consequence of a page fault during
+| copyout.  The probability of a page fault is exceedingly small because
+| the 68040 always reads the destination address and thus the page
+| faults should have already been handled.
+|
+| If the EXC_SR shows that the exception was from supervisor space,
+| then just do a dumb (and slow) memory move.  In a UNIX environment
+| there shouldn't be any supervisor mode floating point exceptions.
+|
+	.global	mem_write
+mem_write:
+	btstb	#5,EXC_SR(%a6)	|check for supervisor state
+	beqs	user_write
+super_write:
+	moveb	(%a0)+,(%a1)+
+	subql	#1,%d0
+	bnes	super_write
+	rts
+user_write:
+	movel	%d1,-(%sp)	|preserve d1 just in case
+	movel	%d0,-(%sp)
+	movel	%a1,-(%sp)
+	movel	%a0,-(%sp)
+	jsr		copyout
+	addw	#12,%sp
+	movel	(%sp)+,%d1
+	rts
+|
+|	mem_read --- read from user or supervisor address space
+|
+| Reads from memory while in supervisor mode.  copyin accomplishes
+| this via a 'moves' instruction.  copyin is a UNIX SVR3 (and later) function.
+| If you don't have copyin, use the local copy of the function below.
+|
+| The FPSP calls mem_read to read the original F-line instruction in order
+| to extract the data register number when the 'Dn' addressing mode is
+| used.
+|
+|Input:
+|	a0 - user source address
+|	a1 - supervisor destination address
+|	d0 - number of bytes to read (maximum count is 12)
+|
+| Like mem_write, mem_read always reads with a supervisor 
+| destination address on the supervisor stack.  Also like mem_write,
+| the EXC_SR is checked and a simple memory copy is done if reading
+| from supervisor space is indicated.
+|
+	.global	mem_read
+mem_read:
+	btstb	#5,EXC_SR(%a6)	|check for supervisor state
+	beqs	user_read
+super_read:
+	moveb	(%a0)+,(%a1)+
+	subql	#1,%d0
+	bnes	super_read
+	rts
+user_read:
+	movel	%d1,-(%sp)	|preserve d1 just in case
+	movel	%d0,-(%sp)
+	movel	%a1,-(%sp)
+	movel	%a0,-(%sp)
+	jsr		copyin
+	addw	#12,%sp
+	movel	(%sp)+,%d1
+	rts
+
+|
+| Use these routines if your kernel doesn't have copyout/copyin equivalents.
+| Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC,
+| and copyin overwrites SFC.
+|
+copyout:
+	movel	4(%sp),%a0	| source
+	movel	8(%sp),%a1	| destination
+	movel	12(%sp),%d0	| count
+	subl	#1,%d0		| dec count by 1 for dbra
+	movel	#1,%d1
+	movec	%d1,%DFC		| set dfc for user data space
+moreout:
+	moveb	(%a0)+,%d1	| fetch supervisor byte
+	movesb	%d1,(%a1)+	| write user byte
+	dbf	%d0,moreout
+	rts
+
+copyin:
+	movel	4(%sp),%a0	| source
+	movel	8(%sp),%a1	| destination
+	movel	12(%sp),%d0	| count
+	subl	#1,%d0		| dec count by 1 for dbra
+	movel	#1,%d1
+	movec	%d1,%SFC		| set sfc for user space
+morein:
+	movesb	(%a0)+,%d1	| fetch user byte
+	moveb	%d1,(%a1)+	| write supervisor byte
+	dbf	%d0,morein
+	rts
+
+	|end

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this