/*
 * QuickThreads -- Threads-building toolkit.
 * Copyright (c) 1993 by David Keppel
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice and this notice
 * appear in all copies.  This software is provided as a
 * proof-of-concept and for demonstration purposes; there is no
 * representation about the suitability of this software for any
 * purpose.
 */

/* axp.s -- assembly support. */

	.text
	.align 4
	.file 2 "axp.s"

	.globl qt_block
	.globl qt_blocki
	.globl qt_abort
	.globl qt_start
	.globl qt_vstart

	/*
	** $16: ptr to function to call once curr is suspended
	**	and control is on r19's stack.
	** $17: 1'th arg to (*$16)(...).
	** $18: 2'th arg to (*$16)(...).
	** $19: sp of thread to resume.
	**
	** The helper routine returns a value that is passed on as the
	** return value from the blocking routine.  Since we don't
	** touch r0 between the helper's return and the end of
	** function, we get this behavior for free.
	*/

	.ent qt_blocki
qt_blocki:
	subq $30,80, $30	/* Allocate save area. */
	stq $26, 0($30)		/* Save registers. */
	stq  $9, 8($30)
	stq $10,16($30)
	stq $11,24($30)
	stq $12,32($30)
	stq $13,40($30)
	stq $14,48($30)
	stq $15,56($30)
	stq $29,64($30)
	.end qt_blocki
	.ent qt_abort
qt_abort:
	addq $16,$31, $27	/* Put argument function in PV. */
	addq $30,$31, $16	/* Save stack ptr in outgoing arg. */
	addq $19,$31, $30	/* Set new stack pointer. */
	jsr $26,($27),0		/* Call helper function. */

	ldq $26, 0($30)		/* Restore registers. */
	ldq  $9, 8($30)
	ldq $10,16($30)
	ldq $11,24($30)
	ldq $12,32($30)
	ldq $13,40($30)
	ldq $14,48($30)
	ldq $15,56($30)
	ldq $29,64($30)

	addq $30,80, $30	/* Deallocate save area. */
	ret $31,($26),1		/* Return, predict===RET. */
	.end qt_abort


	/*
	** Non-varargs thread startup.
	*/
	.ent qt_start
qt_start:
	addq $9,$31,  $16	/* Load up `qu'. */
	addq $10,$31, $17	/* ... user function's `pt'. */
	addq $11,$31, $18	/* ... user function's `userf'. */
	addq $12,$31, $27	/* ... set procedure value to `only'. */
	jsr $26,($27),0		/* Call `only'. */

	jsr $26,qt_error	/* `only' erroniously returned. */
	.end qt_start


	.ent qt_vstart:
qt_vstart:
	/* Call startup function. */
	addq $9,$31, $16	/* Arg0 to `startup'. */
	addq $12,$31, $27	/* Set procedure value. */
	jsr $26,($27),0		/* Call `startup'. */

	/* Call user function. */
	ldt $f16, 0($30)	/* Load fp arg regs. */
	ldt $f17, 8($30)
	ldt $f18,16($30)
	ldt $f19,24($30)
	ldt $f20,32($30)
	ldt $f21,40($30)
	ldq $16,48($30)		/* And integer arg regs. */
	ldq $17,56($30)
	ldq $18,64($30)
	ldq $19,72($30)
	ldq $20,80($30)
	ldq $21,88($30)
	addq $30,96 $30		/* Pop 6*2*8 saved arg regs. */
	addq $11,$31, $27	/* Set procedure value. */
	jsr $26,($27),0		/* Call `vuserf'. */

	/* Call cleanup. */
	addq $9,$31, $16	/* Arg0 to `cleanup'. */
	addq $0,$31, $17	/* Users's return value is arg1. */
	addq $10,$31, $27	/* Set procedure value. */
	jsr $26,($27),0		/* Call `cleanup'. */

	jsr $26,qt_error	/* Cleanup erroniously returned. */
	.end qt_start


	/*
	** Save calle-save floating-point regs $f2..$f9.
	** Also save return pc from whomever called us.
	**
	** Return value from `qt_block' is the same as the return from
	** `qt_blocki'.  We get that for free since we don't touch $0
	** between the return from `qt_blocki' and the return from
	** `qt_block'.
	*/
	.ent qt_block
qt_block:
	subq $30,80, $30	/* Allocate a save space. */
	stq $26, 0($30)		/* Save registers. */
	stt $f2, 8($30)
	stt $f3,16($30)
	stt $f4,24($30)
	stt $f5,32($30)
	stt $f6,40($30)
	stt $f7,48($30)
	stt $f8,56($30)
	stt $f9,64($30)

	jsr $26,qt_blocki	/* Call helper. */
				/* .. who will also restore $gp. */

	ldq $26, 0($30)		/* restore registers. */
	ldt $f2, 8($30)
	ldt $f3,16($30)
	ldt $f4,24($30)
	ldt $f5,32($30)
	ldt $f6,40($30)
	ldt $f7,48($30)
	ldt $f8,56($30)
	ldt $f9,64($30)

	addq $30,80, $30	/* Deallcate save space. */
	ret $31,($26),1		/* Return, predict===RET. */
	.end qt_block