	#
	# 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 "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_vstart


	#
	# 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
