/*  rs6000.s -- MPD assembly code for the RS6000 architecture
 *
 *  Jon Crowcroft, 1991, 1993
 *  Gregg Townsend, 1994
 *
 *  The RS6000 stack grows from high address to low.
 *  A context array is laid out like this:
 *
 *	TOP (stack address + stack size)
 *	--------------------------------------------
 *	  -4	saved SP
 *	  -8	TOC
 *	 -12	LR
 *	 -16	CR
 *	 -20	unused
 *	 -88	GP 13 - 31  (68 bytes)
 *	-232	FP 14 - 31  (144 bytes)
 *	-288	callee's save area (56 bytes)
 * 	 ...
 * 	room for growth
 * 	 ...
 *	  +4	magic word  (should be stored and checked here)
 *	  +0	stack size  (stored here)
 *	--------------------------------------------
 *	BOTTOM (stack address points here)
 */

/*
 * To Do:
 * Check magic number in stack
 * context[context[0]-8] == MAGIC
 * Check stack bounds!!!
 * sp is in context[context[0]-4]
 * sp >=context[context[0]] -> Underflow
 * sp < context -> Overflow
 */

	.file	"rs6000.s"
	.set	stkoff, 288		/* starting stack offset */

/* data entry in Table of Contents */
.toc
T.contextdat: .tc contextdat[tc], .contextdat[rw]
	.globl	.contextdat
	.csect	.contextdat[rw]
.contextdat:
gogogo:
	.long	mpd_startup_context



/* stack problem handlers  (these calls do not return) */

	.csect	mpd_stk_error[PR]

	.extern	.mpd_stk_overflow
	.extern	.mpd_stk_underflow
	.extern	.mpd_stk_corrupted

over:	b	.mpd_stk_overflow
under:	b	.mpd_stk_underflow
bad:	b	.mpd_stk_corrupted



/*  mpd_build_context(code,context,stksize,arg1,arg2,arg3,arg4)
 *               GPR:  3     4       5      6    7    8    9
 *
 *  code	entry point of the code to be executed in the context
 *  context	buffer for holding the context array
 *  stksize	size of this buffer
 *  arg1..arg4	four int-sized arguments to be passed to the code
 *
 */

	.globl	mpd_build_context[ds]	/* runtime linkage space */
	.csect	mpd_build_context[ds]
	.long	.mpd_build_context[PR]
	.long	TOC[tc0]
	.long	0

.toc					/* function entry in TOC */
T.mpd_build_context: .tc mpd_build_context[tc], .mpd_build_context[PR]

	.globl	.mpd_build_context[PR]	/* the program segment */
	.csect	.mpd_build_context[PR]

	.align	2

	st	5, 0(4)		/* save stack size */
	a	4, 4, 5		/* adjust GP 4 to point to stack TOP */
	l	10, T.contextdat(2)

	.using	.contextdat[rw], 10

	/* save code address and args in GP 13 - 17 of context */

	l	13, 0(3)	/* code */
	or	14, 6, 6	/* args 1 */
	or	15, 7, 7	/* args 2 */
	or	16, 8, 8	/* args 3 */
	or	17, 9, 9	/* args 4 */
	stm	13, -88(4)	/* save GP registers */

	/* save miscellaneous registers */

	si	5, 4, stkoff	/* safe first stk offset */
	st	5, -4(4)	/* SP */

	st	2, -8(4)	/* TOC */

	l	5, gogogo	
	st	5, -12(4)	/* startup code -> LR slot  */

	mfcr	0
	st	0, -16(4)	/* CR */

	brl			/* ret */

/* on entry here, r3 has context, r13 new Link Reg - don't touch r13-31 */
.globl mpd_startup_context
mpd_startup_context: /* only need args first time proc starts */
	mtlr	13		/* code start -> link reg */
	or	3, 14, 14	/* args 1 */
	or	4, 15, 15	/* args 2 */
	or	5, 16, 16	/* args 3 */
	or	6, 17, 17	/* args 4 */
	brl
	b	.mpd_stk_underflow 	/* if anyone returns - underflow! */
/* end mpd_build_context */



/*
 * mpd_chg_context(newctx, oldctx)
 *                GPR 3    GPR 4
 *
 *  a bit like Called Routines job - see Ch 4 - 13 in Assembler Ref
 */
	.globl	mpd_chg_context[ds]	/* runtime linkage space */
	.csect	mpd_chg_context[ds]
	.long	.mpd_chg_context[PR]
	.long	TOC[tc0]
	.long	0
.toc				/* function entry in TOC */
T.mpd_chg_context: .tc mpd_chg_context[tc], .mpd_chg_context[PR]

	.globl	.mpd_chg_context[PR]
	.csect	.mpd_chg_context[PR]
	l	10, T.contextdat(2)
	.using	.contextdat[rw], 10

	cmpi	0, 0, 4, 0
	beq	load
	l	5, 0(4)		/* to top */
	a	4, 4, 5		/* get to top of stk */

	/*
	 * Save Old Context
	 */
	st	1, -4(4)	/* SP */
	st	2, -8(4)	/* TOC */
	mflr	0
	st	0, -12(4)	/* LR (return address) */
	mfcr	0
	st	0, -16(4)	/* CR */

	stm	13, -88(4)	/* GPRs 13-31 */

	stfd	14, -232(4)	/* FPRs */
	stfd	15, -224(4)
	stfd	16, -216(4)
	stfd	17, -208(4)
	stfd	18, -200(4)
	stfd	19, -192(4)
	stfd	20, -184(4)
	stfd	21, -176(4)
	stfd	22, -168(4)
	stfd	23, -160(4)
	stfd	24, -152(4)
	stfd	25, -144(4)
	stfd	26, -136(4)
	stfd	27, -128(4)
	stfd	28, -120(4)
	stfd	29, -112(4)
	stfd	30, -104(4)
	stfd	31, -96(4)

	/*
	 * Restore New Context
	 */
load:
	l	5, 0(3)
	a	3, 3, 5
	l	1, -4(3)	/* sp from newcontext -> sp */

	lm	13, -88(3)	/* restore GPRs 13-31 -> context */

	lfd	14, -232(3)	/* FPRs */
	lfd	15, -224(3)
	lfd	16, -216(3)
	lfd	17, -208(3)
	lfd	18, -200(3)
	lfd	19, -192(3)
	lfd	20, -184(3)
	lfd	21, -176(3)
	lfd	22, -168(3)
	lfd	23, -160(3)
	lfd	24, -152(3)
	lfd	25, -144(3)
	lfd	26, -136(3)
	lfd	27, -128(3)
	lfd	28, -120(3)
	lfd	29, -112(3)
	lfd	30, -104(3)
	lfd	31, -96(3)

/* don't touch 13-31 */
	l	2, -8(3)	/* TOC -> context */
	l	0, -12(3)	/* LR -> context */
	mtlr	0		/* get LR */
	l	0, -16(3)	/* CR -> context */
	mtcr	0		/* get CR */
	brl			/* execute new context */
	brl			/* ?? -- seems necessary */
/* end mpd_chg_context */



/*
 * mpd_check_stk() -- check that the stack is not overflowing
 */
	.globl	mpd_check_stk[ds]	/* runtime linkage space */
	.csect	mpd_check_stk[ds]
	.long	.mpd_check_stk[PR]
	.long	TOC[tc0]
	.long	0

.toc					/* function entry in TOC */
T.mpd_check_stk: .tc mpd_check_stk[tc], .mpd_check_stk[PR]
	.globl	.mpd_check_stk[PR]
	.csect	.mpd_check_stk[PR]

	brl			/* return */

/* end	mpd_check_stk */
