
/*
 *	setjmp.c	-	setjmp() and longjmp() routines for Hitachi SH series
 *
 *	Copyright © 1999 Metrowerks, Inc.  All Rights Reserved.
 *
 *
 *	THEORY OF OPERATION
 *
 *	The runtime support routines __setjmp() and longjmp() support the C <setjmp.h>
 *	facilities. __setjmp() captures the state of the program in a jmp_buf data structure
 *	which has the following C definition:
 *
 *		typedef long jmp_buf[13];		 // saved pr/r8-r15/fr12-fr15
 *
 *	setjmp() and longjmp() are defined as follows:
 *
 *		int __setjmp(jmp_buf env);
 *		#define setjmp(env) __setjmp(env)
 *		void longjmp(jmp_buf env, int val);
 *
 */


/*	Private Types	*/


typedef struct __jmp_buf {
	unsigned long	pr;
	unsigned long	r8;
	unsigned long	r9;
	unsigned long	r10;
	unsigned long	r11;
	unsigned long	r12;
	unsigned long	r13;
	unsigned long	r14;
	unsigned long	r15;
	unsigned long	fr12;
	unsigned long	fr13;
	unsigned long	fr14;
	unsigned long	fr15;
} __jmp_buf;


/*	Prototypes	*/


#ifdef __cplusplus
extern "C" {
#endif

int __setjmp(__jmp_buf *env);
void longjmp(__jmp_buf *env, int val);

#ifdef __cplusplus
}
#endif


/*
 *	__setjmp	-	C setjmp() routine
 *
 *	On entry R4 points to a jmp_buf struct. On exit, R0 is 0.
 *
 */

asm int __setjmp(register __jmp_buf *env)
{
	.set	noreorder
	STS		PR,R0
	MOV.L	R0,@(__jmp_buf.pr,env);
	MOV.L	R8,@(__jmp_buf.r8,env);
	MOV.L	R9,@(__jmp_buf.r9,env);
	MOV.L	R10,@(__jmp_buf.r10,env);
	MOV.L	R11,@(__jmp_buf.r11,env);
	MOV.L	R12,@(__jmp_buf.r12,env);
	MOV.L	R13,@(__jmp_buf.r13,env);
	MOV.L	R14,@(__jmp_buf.r14,env);
	MOV.L	R15,@(__jmp_buf.r15,env);
	MOV		__jmp_buf.fr12,R0;
	FMOV.S	FR12,@(R0,env);
	MOV		__jmp_buf.fr13,R0;
	FMOV.S	FR13,@(R0,env);
	MOV		__jmp_buf.fr14,R0;
	FMOV.S	FR14,@(R0,env);
	MOV		__jmp_buf.fr15,R0;
	FMOV.S	FR15,@(R0,env);
	RTS;
	MOV		0,R0;
}


/*
 *	longjmp		-	C longjmp() routine
 *
 *	On entry R4 points to a jmp_buf struct and R5 contains the return value.
 *	On exit, R0 contains 1 if R5 was 0, otherwise it contains the value from R5.
 *
 */

asm void longjmp(register __jmp_buf *env, register int val)
{
	.set	noreorder
	MOV.L	@(__jmp_buf.pr,env),R0;
	LDS		R0,PR
	MOV.L	@(__jmp_buf.r8,env),R8;
	MOV.L	@(__jmp_buf.r9,env),R9;
	MOV.L	@(__jmp_buf.r10,env),R10;
	MOV.L	@(__jmp_buf.r11,env),R11;
	MOV.L	@(__jmp_buf.r12,env),R12;
	MOV.L	@(__jmp_buf.r13,env),R13;
	MOV.L	@(__jmp_buf.r14,env),R14;
	MOV.L	@(__jmp_buf.r15,env),R15;
	MOV		__jmp_buf.fr12,R0;
	FMOV.S	@(R0,env),FR12;
	MOV		__jmp_buf.fr13,R0;
	FMOV.S	@(R0,env),FR13;
	MOV		__jmp_buf.fr14,R0;
	FMOV.S	@(R0,env),FR14;
	MOV		__jmp_buf.fr15,R0;
	FMOV.S	@(R0,env),FR15;

	MOV		val,R0;
	TST		R0,R0;
	BF		L1;
	MOV		0,R0;
L1:
	RTS;
	NOP;
}
