/*  v68s.s -- System V/68 assembly language code
 *
 *
 *  A context array is laid out like this:
 *
 *	saved registers
 *  	magic word for checking integrity
 *	unused stack space
 *	saved pc		<--- saved sp points here  
 *	valid stack data (if any)
 *	address of error handler (in case of erroneous return)
 *	arguments from mpd_build_context call
 *
 *  Registers are always saved at the base of the array. a0/a1/d0/d1 aren't
 *  saved because C doesn't expect them to survive over function calls.
 *  The set does include sp, so we don't need to handle it separately.
 */ 

#define MAGIC 618033989		/* any unlikely long integer */
#define RMASK 0xFCFC		/* register save mask (d2-d7, a2-a6, sp) */
#define RSIZE 48		/* size of register save area */
	
	data
curr_stack:			/* saves addr of current context (stack) */
	long	dummy_stack
dummy_stack:			/* fake initial context */
	space	RSIZE		/* room to save initial register set */
	long	MAGIC		/* magic word to pass the sanity check */

	text



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


	global	mpd_build_context
mpd_build_context:
	mov.l	%a6,-(%sp)	/* save caller's frame pointer */
	mov.l	12(%sp),%a1	/* a1 = pointer to context array */
	mov.l	%a1,%a6
	add.l	16(%sp),%a6	/* a6 = pointer to end of context's stack */

	mov.l	32(%sp),-(%a6)	/* push arg4 */
	mov.l	28(%sp),-(%a6)	/* push arg3 */
	mov.l	24(%sp),-(%a6)	/* push arg2 */
	mov.l	20(%sp),-(%a6)	/* push arg1 */

	mov.l	&under,-(%a6)	/* push error addr in case context returns */
	mov.l	8(%sp),-(%a6)	/* push address for starting execution */

	mov.l	%sp,%a0		/* save pointer to stack we were called on */
	mov.l	%a6,%sp		/* set user stack pointer */
	movm.l	&RMASK,(%a1)	/* save registers in user context block */
	add.l	&RSIZE,%a1
	mov.l	&MAGIC,(%a1)	/* store magic word for integrity checking */
	mov.l	%a0,%sp		/* restore our stack pointer */
	mov.l	(%sp)+,%a6	/* restore caller's frame pointer */
	rts			/* return */



/*  mpd_chg_context(newstack) -- switch context to the specified stack  */

	global	mpd_chg_context
mpd_chg_context:
	mov.l	curr_stack,%a0	/* load address of current context stack */
	movm.l	&RMASK,(%a0)	/* save registers (including sp) */
	add.l	&RSIZE,%a0
	cmp.l	%sp,%a0		/* check that stack isn't overflowing */
	bcs	over
	cmp.l	(%a0),&MAGIC	/* catch earlier overflow (maybe) */
	bne	over
	mov.l	4(%sp),%a0	/* load address of new context */
	lea	RSIZE(%a0),%a1
	cmp.l	(%a1),&MAGIC	/* make sure new stack looks okay */
	bne	bad
	mov.l	%a0,curr_stack	/* save address of new context */
	movm.l	(%a0),&RMASK	/* load new context (including sp) */
	rts			/* return into new context */



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

	global	mpd_check_stk
mpd_check_stk:
	mov.l	curr_stack,%a0
	add.l	&RSIZE,%a0
	cmp.l	%sp,%a0
	bcs	over
	rts



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

over:	jsr	mpd_stk_overflow
under:	jsr	mpd_stk_underflow
bad:	jsr	mpd_stk_corrupted
