/*  mips.s -- assembly code for the MIPS RISC architecture
 *
 * ======> for SGI systems, this code assumes the "O32" ABI  (see "man abi")
 *
 *  A MIPS context array is laid out like this:
 *
 *	saved sp register ------------------------------|
 *	magic word for checking integrity		|
 *	unused stack space				| 
 *	saved registers, including $31 (return addr) <--- saved sp points here
 *	older stack data
 *
 *  Both regular and floating point registers are saved.  As of 7/91 the
 *  current Dec and SGI compilers don't seem to utilize f.p. temporaries,
 *  but gcc does.
 */

#define MAGIC 61407		/* an unlikely integer */

#define ASIZE 16		/* space for callee to save 4 arguments */
#define RSIZE 88		/* space for 10 saved registers and 6 FP regs */
	
	.text
	.align	2



/*  mpd_build_context(code,context,stksize,arg1,arg2,arg3,arg4)
 *
 *  args passed in:   $4    $5      $6     $7  16($sp) .. 24($sp)
 *
 *  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
 *
 *  All we need to do is set up a context that will execute the startup
 *  code, below, when activated for the first time.
 */


	.globl	mpd_build_context
	.ent	mpd_build_context
mpd_build_context:
	.frame	$sp, 0, $31
	li	$3, MAGIC
	sw	$3, 4($5)	/* save magic word */
	addu	$2, $5, $6	/* end of buffer */
	subu	$2, ASIZE+RSIZE	/* $2 =  new stack pointer */
	sw	$2, 0($5)	/* save in context array */
	sw	$7, 48($2)	/* save first arg in $16 slot */
	lw	$3, 16($sp)
	sw	$3, 52($2)	/* save second arg in $17 slot */
	lw	$3, 20($sp)
	sw	$3, 56($2)	/* save third arg in $18 slot */
	lw	$3, 24($sp)
	sw	$3, 60($2)	/* save fourth arg in $19 slot */
	sw	$4, 64($2)	/* save entry point in $20 slot */
	la	$3, startup
	sw	$3, 84($2)	/* save startup address in $31 slot */
	j	$31		/* return */

startup:	
	move	$4,$16		/* load arg registers for first-time call */
	move	$5,$17
	move	$6,$18
	move	$7,$19
	la	$31,under	/* detect underflow if called code returns */
	move	$25,$20		/* MIPS ABI requires $25 for indirect call */
	j	$25		/* jump to entry point */
	.end	mpd_build_context



/*  mpd_chg_context (newctx, oldctx) -- switch to the specified context 
 *
 *  args passed in:   $4    $5
 */

	.globl	mpd_chg_context
	.ent	mpd_chg_context
mpd_chg_context:
	subu	$sp, RSIZE	/* make room on stack for saving registers */
	.frame	$sp, RSIZE, $31

	beq	$5, 0, savedone	/* don't use oldctx if 0 */

	li	$13, MAGIC	/* magic constant */
	lw	$9, 4($5)	/* old magic word */
	ble	$sp, $5, over	/* if stack is currently overflowing */
	lw	$10, 4($4)	    /* new magic word */
	bne	$9, $13, over	/* if it overflowed before & clobbered magic */
	bne	$10, $13, bad	    /* if new context isn't intact */

	.mask	0xC0FF0000, -4
	sw	$sp, 0($5)	/* save stack pointer, then registers */
	sd	$30, 80($sp)	/* includes $31, our caller's return address */
	sd	$22, 72($sp)
	sd	$20, 64($sp)
	sd	$18, 56($sp)
	sd	$16, 48($sp)
	.fmask	0xFFF00000, -4
	s.d	$f30, 40($sp)	/* save floating-point registers */
	s.d	$f28, 32($sp)
	s.d	$f26, 24($sp)
	s.d	$f24, 16($sp)
	s.d	$f22, 8($sp)
	s.d	$f20, 0($sp)

savedone:

	lw	$sp, 0($4)	/* load new stack pointer, then registers */
	ld	$30, 80($sp)	/* includes $31, the resumption address */
	ld	$22, 72($sp)
	ld	$20, 64($sp)
	ld	$18, 56($sp)
	ld	$16, 48($sp)
	l.d	$f30, 40($sp)	/* load new floating-point registers */
	l.d	$f28, 32($sp)
	l.d	$f26, 24($sp)
	l.d	$f24, 16($sp)
	l.d	$f22, 8($sp)
	l.d	$f20, 0($sp)
	addu	$sp, RSIZE	/* adjust stack pointer to remove reg area */
	j	$31		/* return into new context */

	.end	mpd_chg_context



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

	.globl	mpd_check_stk
	.ent	mpd_check_stk
mpd_check_stk:
	.frame	$sp, 0, $31

	ble	$sp, $4, over	/* check that we haven't grown beyond bounds */
	j	$31		/* return */



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

over:	jal	mpd_stk_overflow
under:	jal	mpd_stk_underflow
bad:	jal	mpd_stk_corrupted

	.end	mpd_check_stk
