/*  vax.s -- Vax assembly code  (Unix or Ultrix)
 *
 *  A Vax context array is laid out like this:
 *
 *	saved fp register -------------------------|
 *	magic word for checking integrity	   |
 *	unused stack space			   |
 *	stack frame for continuing execution	<--- saved fp points here
 *	current stack data, if any
 *	stack frame for error handler in case of erroneous return
 *	arguments from mpd_build_context call
 *
 *  General registers 6-11 are saved in the stack frame when changing context,
 *  along with pc, fp, and ap.  We don't save r0-r5 because C doesn't expect
 *  them to survive a function call.
 */

#define MAGIC $618033989		/* any unlikely long integer */
	
	.text
	.align	1



/*  mpd_build_context(code,buf,stksize,a1,a2,a3,a4) -- create a new context.
 *
 *  code	entry point of the code to be executed in the context
 *  buf		a buffer for holding the context array
 *  stksize	size of the buffer
 *  a1 - a4	four int-sized arguments to be passed to the code
 */


	.globl	_mpd_build_context
_mpd_build_context:
	.word	0		/* save no registers */
	addl3	8(ap),12(ap),r1	/* r1 = end of stack */

	/* copy the arguments into the stack buffer */
	movl	28(ap),-(r1)	/* arg 4 */
	movl	24(ap),-(r1)	/* arg 3 */
	movl	20(ap),-(r1)	/* arg 2 */
	movl	16(ap),-(r1)	/* arg 1 */
	movl	$4,-(r1)	/* arg count */
	movl	r1,r3		/* save the arg pointer */

	/* build a stack frame to catch (invalid) return from code */
	movab	under,-(r1)	/* pc points to underflow handler */
	movl	$0,-(r1)	/* fp will not be used */
	movl	$0,-(r1)	/* ap will not be used */
	movl	$0,-(r1)	/* psw */
	movl	$0,-(r1)	/* condition handler */
	
	/* build another stack frame to "return" to the given entry point */
	addl3	$2,4(ap),-(r1)	/* pc = entry point + 2 (skip reg mask) */
	movab	4(r1),-(r1)	/* fp = pointer to underflow frame */
	movl	r3,-(r1)	/* ap */
	movl	$0,-(r1)	/* psw */
	movl	$0,-(r1)	/* condition handler */

	/* save frame pointer, and also magic word for detecting underflow */
	movl	8(ap),r2	/* r2 = beginning of stack buffer */
	movl	r1,(r2)+	/* save pointer to new frame we just made */
	movl	MAGIC,(r2)	/* store magic word for checking integrity */
	ret			/* return */



/*  mpd_chg_context(newstk,oldstk) -- switch context to the specified stack  */

	.globl	_mpd_chg_context
_mpd_chg_context:
	.word	0xFC0		/* save the registers C assumes are preserved */
	movl	8(ap),r1	/* r1 = old stack */
	movl	4(ap),r2	/* r2 = new stack */

	tstl	r1		/* see if we're saving the context */
	jeql	first

	cmpl	sp,r1		/* catch current stack overflow */
	jleq	over
	cmpl	MAGIC,4(r1)	/* catch earlier overflow (maybe) */
	jneq	over
	movl	fp,(r1)		/* save old fp */

first:
	cmpl	MAGIC,4(r2)	/* check that new stack looks okay */
	jneq	bad

	movl	(r2),fp		/* set fp for new context */
	ret			/* return into new context */



/*  mpd_check_stk(context) -- check that the stack is not overflowing  */

	.globl	_mpd_check_stk
_mpd_check_stk:
	.word	0
	cmpl	sp,4(ap)
	jleq	over
	ret



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

over:	calls	$0,_mpd_stk_overflow
under:	calls	$0,_mpd_stk_underflow
bad:	calls	$0,_mpd_stk_corrupted
