/*
 * $Id: stdlib_setjmp.c,v 1.3 2005-01-02 09:07:18 obarthel Exp $
 *
 * :ts=4
 *
 * Portable ISO 'C' (1994) runtime library for the Amiga computer
 * Copyright (c) 2002-2005 by Olaf Barthel <olsen@sourcery.han.de>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Neither the name of Olaf Barthel nor the names of contributors
 *     may be used to endorse or promote products derived from this
 *     software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#if defined(__GNUC__)

/****************************************************************************/

#if defined(SMALL_DATA)
#define A4(x) "a4@(" #x ":W)"
#elif defined(SMALL_DATA32)
#define A4(x) "a4@(" #x ":L)"
#else
#define A4(x) #x
#endif /* SMALL_DATA */

/****************************************************************************/

#if defined(__mc68020__)

/****************************************************************************/

asm("                                                                            \n\
                                                                                 \n\
AFB_68881 = 4                                                                    \n\
AttnFlags = 297                                                                  \n\
                                                                                 \n\
	.text                                                                         \n\
	.even                                                                         \n\
                                                                                 \n\
	.globl	_setjmp                                                              \n\
                                                                                 \n\
_setjmp:                                                                         \n\
                                                                                 \n\
	movel	a0,sp@-						| save A0                                       \n\
	moveal	sp@(8),a0					| (struct __jmp_buf *) env                   \n\
	movel	sp@(4),a0@					| remember the return address                   \n\
	moveml	d1-a6,a0@(4:W)				| save all registers, except for D0 and A7   \n\
	movel	sp@+,a0@(32:W)				| put the old A0 where it belongs               \n\
	movel	sp,a0@(60:W)				| put the old A7 where it belongs               \n\
                                                                                 \n\
	moveal	"A4(_SysBase)",a1                                                    \n\
	btst	#AFB_68881,a1@(AttnFlags:W)	| is there an FPU installed?              \n\
	beq		l0							| skip the following if not                     \n\
                                                                                 \n\
	fmovemx	fp0-fp7,a0@(64:W)			| save all floating point registers          \n\
                                                                                 \n\
l0:	moveq	#0,d0						| always return 0                               \n\
	rts                                                                           \n\
                                                                                 \n\
");

/****************************************************************************/

#if defined(STACK_EXTENSION)

/****************************************************************************/

asm("                                                                            \n\
                                                                                 \n\
AFB_68881 = 4                                                                    \n\
AttnFlags = 297                                                                  \n\
                                                                                 \n\
	.text                                                                         \n\
	.even                                                                         \n\
                                                                                 \n\
	.globl	_longjmp                                                             \n\
	.globl	___stkrst                                                            \n\
                                                                                 \n\
_longjmp:                                                                        \n\
                                                                                 \n\
	moveal	sp@(4),a0					| (struct __jmp_buf *) env                   \n\
	movel	sp@(8),d2					| (int) status                                  \n\
                                                                                 \n\
	tstl	d2                                                                      \n\
	bne		l1							| skip the following if result is non-zero      \n\
                                                                                 \n\
	moveq	#1,d2						| make sure that the result is always non-zero     \n\
                                                                                 \n\
l1:	movel	a0@(60:W),d0				| get the stack pointer address to restore   \n\
	jbsr	___stkrst					| restore the stack frame                       \n\
	movel	d2,d0						| get the return code back                         \n\
                                                                                 \n\
	moveal	"A4(_SysBase)",a1                                                    \n\
	btst	#AFB_68881,a1@(AttnFlags:W)	| is there an FPU installed?              \n\
	beq		l2							| skip the following if not                     \n\
                                                                                 \n\
	fmovemx	a0@(64:W),fp0-fp7			| restore all floating point registers       \n\
                                                                                 \n\
l2:	moveml	a0@(4:W),d1-d7				| restore all data registers              \n\
	moveml	a0@(36:W),a1-a7				| restore almost all address registers, except for A0 \n\
	movel	a0@,sp@						| restore A0                                    \n\
	moveal	a0@(32:W),a0				| and return to the address setjmp() was called from  \n\
	rts                                                                           \n\
                                                                                 \n\
");

/****************************************************************************/

#else

/****************************************************************************/

asm("                                                                      \n\
                                                                           \n\
AFB_68881 = 4                                                              \n\
AttnFlags = 297                                                            \n\
                                                                           \n\
	.text                                                                   \n\
	.even                                                                   \n\
                                                                           \n\
	.globl	_longjmp                                                       \n\
                                                                           \n\
_longjmp:                                                                  \n\
                                                                           \n\
	moveal	sp@(4),a0					| (struct __jmp_buf *) env             \n\
	movel	sp@(8),d0					| (int) status                            \n\
                                                                           \n\
	tstl	d0                                                                \n\
	bne		l1							| skip the following if result is non-zero\n\
                                                                           \n\
	moveq	#1,d0						| make sure that the result is always non-zero\n\
                                                                           \n\
l1:	moveal	"A4(_SysBase)",a1                                           \n\
	btst	#AFB_68881,a1@(AttnFlags:W)	| is there an FPU installed?        \n\
	beq		l2							| skip the following if not               \n\
                                                                           \n\
	fmovemx	a0@(64:W),fp0-fp7			| restore all floating point registers \n\
                                                                           \n\
l2:	moveml	a0@(4:W),d1-d7				| restore all data registers        \n\
	moveml	a0@(36:W),a1-a7				| restore almost all address registers, except for A0\n\
	movel	a0@,sp@						| restore A0                              \n\
	moveal	a0@(32:W),a0				| and return to the address setjmp() was called from\n\
	rts                                                                     \n\
                                                                           \n\
");

/****************************************************************************/

#endif /* STACK_EXTENSION */

/****************************************************************************/

#elif defined(__mc68000__) 

/****************************************************************************/

asm("                                                                     \n\
                                                                          \n\
	.text                                                                  \n\
	.even                                                                  \n\
                                                                          \n\
	.globl	_setjmp                                                       \n\
                                                                          \n\
_setjmp:                                                                  \n\
                                                                          \n\
	movel	a0,sp@-						| save A0                                \n\
	moveal	sp@(8),a0					| (struct __jmp_buf *) env            \n\
	movel	sp@(4),a0@					| remember the return address            \n\
	moveml	d1-a6,a0@(4:W)				| save all registers, except for D0 and A7\n\
	movel	sp@+,a0@(32:W)				| put the old A0 where it belongs        \n\
	movel	sp,a0@(60:W)				| put the old A7 where it belongs        \n\
	moveq	#0,d0						| always return 0                           \n\
	rts                                                                    \n\
                                                                          \n\
");

/****************************************************************************/

#if defined(STACK_EXTENSION)

/****************************************************************************/

asm("                                                                     \n\
                                                                          \n\
	.text                                                                  \n\
	.even                                                                  \n\
                                                                          \n\
	.globl	_longjmp                                                      \n\
	.globl	___stkrst                                                     \n\
                                                                          \n\
_longjmp:                                                                 \n\
                                                                          \n\
	moveal	sp@(4),a0					| (struct __jmp_buf *) env            \n\
	movel	sp@(8),d2					| (int) status                           \n\
                                                                          \n\
	tstl	d2                                                               \n\
	bne		l1							| skip the following if result is non-zero\n\
                                                                          \n\
	moveq	#1,d2						| make sure that the result is always non-zero\n\
                                                                            \n\
l1:	movel	a0@(60:W),d0				| get the stack pointer address to restore\n\
	jbsr	___stkrst					| restore the stack frame                \n\
	movel	d2,d0						| get the return code back                  \n\
                                                                          \n\
	moveml	a0@(4:W),d1-d7				| restore all data registers          \n\
	moveml	a0@(36:W),a1-a7				| restore almost all address registers, except for A0\n\
	movel	a0@,sp@						| restore A0                             \n\
	moveal	a0@(32:W),a0				| and return to the address setjmp() was called from\n\
	rts                                                                    \n\
                                                                          \n\
");

/****************************************************************************/

#else

/****************************************************************************/

asm("                                                                     \n\
                                                                          \n\
	.text                                                                  \n\
	.even                                                                  \n\
                                                                          \n\
	.globl	_longjmp                                                      \n\
                                                                          \n\
_longjmp:                                                                 \n\
                                                                          \n\
	moveal	sp@(4),a0					| (struct __jmp_buf *) env            \n\
	movel	sp@(8),d0					| (int) status                           \n\
                                                                          \n\
	tstl	d0                                                               \n\
	bne		l1							| skip the following if result is non-zero\n\
                                                                          \n\
	moveq	#1,d0						| make sure that the result is always non-zero\n\
                                                                          \n\
l1:	moveml	a0@(4:W),d1-d7				| restore all data registers       \n\
	moveml	a0@(36:W),a1-a7				| restore almost all address registers, except for A0\n\
	movel	a0@,sp@						| restore A0                             \n\
	moveal	a0@(32:W),a0				| and return to the address setjmp() was called from\n\
	rts                                                                    \n\
                                                                          \n\
");

/****************************************************************************/

#endif /* STACK_EXTENSION */

/****************************************************************************/

#elif defined(__PPC__)

/****************************************************************************/

#if defined(STACK_EXTENSION)

/****************************************************************************/

#error "STACK_EXTENSION is not supported on the PowerPC"

/****************************************************************************/

#else

/****************************************************************************/

#ifdef PPC_FLOATING_POINT_SUPPORT

__asm("							\n\
								\n\
	.text						\n\
	.align 2					\n\
								\n\
	.globl setjmp				\n\
								\n\
setjmp:							\n\
								\n\
	mflr	r10					\n\
	mfcr	r11					\n\
	mr		r12, r1				\n\
	stmw	r10, 0(r3)			\n\
	stfd	f14, 88(r3)			\n\
	stfd	f15, 96(r3)			\n\
	stfd	f16, 104(r3)		\n\
	stfd	f17, 112(r3)		\n\
	stfd	f18, 120(r3)		\n\
	stfd	f19, 128(r3)		\n\
	stfd	f20, 136(r3)		\n\
	stfd	f21, 144(r3)		\n\
	stfd	f22, 152(r3)		\n\
	stfd	f23, 160(r3)		\n\
	stfd	f24, 168(r3)		\n\
	stfd	f25, 176(r3)		\n\
	stfd	f26, 184(r3)		\n\
	stfd	f27, 192(r3)		\n\
	stfd	f28, 200(r3)		\n\
	stfd	f29, 208(r3)		\n\
	stfd	f30, 216(r3)		\n\
	stfd    f31, 224(r3)		\n\
	li		r3, 0				\n\
	blr							\n\
								\n\
");

__asm("							\n\
	.text						\n\
	.align 2					\n\
								\n\
	.globl longjmp				\n\
								\n\
longjmp:						\n\
								\n\
	lmw		r10,0(r3)			\n\
	mtlr	r10					\n\
	mtcr	r11					\n\
	mr		r1,r12				\n\
	lfd		f14, 88(r3)			\n\
	lfd		f15, 96(r3)			\n\
	lfd		f16, 104(r3)		\n\
	lfd		f17, 112(r3)		\n\
	lfd		f18, 120(r3)		\n\
	lfd		f19, 128(r3)		\n\
	lfd		f20, 136(r3)		\n\
	lfd		f21, 144(r3)		\n\
	lfd		f22, 152(r3)		\n\
	lfd		f23, 160(r3)		\n\
	lfd		f24, 168(r3)		\n\
	lfd		f25, 176(r3)		\n\
	lfd		f26, 184(r3)		\n\
	lfd		f27, 192(r3)		\n\
	lfd		f28, 200(r3)		\n\
	lfd		f29, 208(r3)		\n\
	lfd		f30, 216(r3)		\n\
	lfd		f31, 224(r3)		\n\
	cmpwi	r4, 0				\n\
	bne		1f					\n\
	li		r3,1				\n\
	blr							\n\
1:								\n\
	mr		r3, r4				\n\
	blr							\n\
								\n\
");
#else
__asm("							\n\
								\n\
	.text						\n\
	.align 2					\n\
								\n\
	.globl setjmp				\n\
								\n\
setjmp:							\n\
								\n\
	mflr	r10					\n\
	mfcr	r11					\n\
	mr		r12, r1				\n\
	stmw	r10, 0(r3)			\n\
	li		r3, 0				\n\
	blr							\n\
								\n\
");

__asm("							\n\
	.text						\n\
	.align 2					\n\
								\n\
	.globl longjmp				\n\
								\n\
longjmp:						\n\
								\n\
	lmw		r10,0(r3)			\n\
	mtlr	r10					\n\
	mtcr	r11					\n\
	mr		r1,r12				\n\
	cmpwi	r4, 0				\n\
	bne		1f					\n\
	li		r3,1				\n\
	blr							\n\
1:								\n\
	mr		r3, r4				\n\
	blr							\n\
								\n\
");

#endif /* defined PPC_FLOATING_POINT_SUPPORT */

#endif /* defined STACK_EXTENSION */

/****************************************************************************/

#endif /* PPC */

/****************************************************************************/

#endif /* __GNUC__ */
