	.file	"swap.s.vax"
#	ident	"%W%"
###############################################################################
#			Copyright (c) 1984 AT&T
#	  		  All Rights Reserved  	
#
#	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
#	
#	The copyright notice above does not evidence any   	
#	actual or intended publication of such source code.
#
###############################################################################

#	swap of DEDICATED
# call swap(*running_task, *to_run_task, is_new_child, running_is_terminated)
# This routine saves the fp in running's t_framep.
# If running is a SHARED task, we must save its stack size as well,
# although the stack does not need to be copied out here.
# It then restores to_run's t_framep to be the current fp.
# If to_run is a new child, it explicitly restores the registers from
# New_task_regs.  If to_run is not a new child, it simply returns.
# If running_task is TERMINATED, then we don't need to do a save.

	.globl _swap
	.align	1
_swap:
	.word	0xfc0		# entry mask; save all user regs (r11-r6)
	movl	8(ap),r2	# r2 = to_run
	movl	16(ap),r1	# r1 = running_is_terminated
	cmpl	$1,r1		# if running is TERMINATED
	jeql	.L_RESTORE	#	skip save
	movl	4(ap),r1	# r1 = running

	# save state of running task
	movl	fp,20(r1)	# running->t_framep = fp
	movl	52(r1),r0	# r0 = running->t_mode
	cmpl	$2,r0		# if running->t_mode == SHARED
	jneq	.L_RESTORE
	# the code here to save the t_size is the same as for sswap

	subl3	sp,32(r1),r0		# r0 = running->t_basep - sp
					# (size in bytes)
	divl3	$4,r0,36(r1)		# running->t_size = r0 / 4 (int)

.L_RESTORE:
	movl	12(ap),r1	# r1 = is_new_child

	# restore state of to_run_task
	movl	20(r2),fp	# fp = to_run->t_framep

	# if is_new_child, restore registers
	tstl	r1
	jeql	.L_RET
	# new child task effectively returns from task::task, so we need
	# to set the return value to "this"
	movl	24(r2),r0		# r0 = to_run->th
	moval	_New_task_regs,r2	# r2 = address of New_task_regs
	movl	0(r2),r6
	movl	4(r2),r7
	movl	8(r2),r8
	movl	12(r2),r9
	movl	16(r2),r10
	movl	20(r2),r11
.L_RET:
	ret

#	swap of SHARED
# sswap(*running, *prevOnStack, *to_run, is_new_child, running_is_terminated)
# This routine saves the fp in running's t_framep and the stack size in t_size.
# Then it copies out the target stack to prevOnStack's t_savearea. 
# If to_run is not a new child, it then copies the saved stack of to_run
# (from t_savearea) to the target stack, and then restores to_run's t_framep
# to be the current fp.  We don't need to restore state of a child 
# to_run object, because it's already in place.
# If running_task is TERMINATED, then we don't need to do a save,
# and if running_task is TERMINATED and equals prevOnStack, then we don't
# have to do the stack copy.
	.globl _sswap
	.align	1
_sswap:
	.word	0xfc0		# entry mask; save all user regs (r11-r6)
	movl	4(ap),r1		# r1 = running
	movl	8(ap),r11		# r11 = prevOnStack
	movl	20(ap),r0		# r0 = running_is_terminated
	cmpl	$1,r0			# if running is TERMINATED
	jeql	.L_SKIP			#	skip save
		#save hw state of running
	movl	fp,20(r1)		# running->t_framep = fp
	subl3	sp,32(r1),r0		# r0 = running->t_basep - sp
					# (size in bytes)
	divl3	$4,r0,36(r1)		# running->t_size = r0 / 4 (int)
	jmp	.L_SAVE

.L_SKIP:	#if running is TERMINATED and running == prevOnStack,
		#then we can skip the stack copy too
	cmpl	r1,r11		# if running == prevOnStack
	jeql	.L_REST			#	skip save

.L_SAVE:	#copy out target stack to prevOnStack->t_savearea
	movl	36(r11),r10		# r10 = prevOnStack->t_size (count)
	pushl	r10
	calls	$1,_swap_call_new	# get count bytes of storage
	ashl	$2,r10,r10		# scale r10 to bytes
	addl2	r10,r0			# r0 = base of new space, plus 1
	subl2	$4,r0			# r0 = base of new stack (to)
	movl	r0,40(r11)		# prevOnStack->t_savearea = r0 (to)
	movl	32(r11),r2		# r2 = prevOnStack->t_basep (from)
	movl	36(r11),r10		# r10 = prevOnStack->t_size (count)
.L1:		#copy out loop
	tstl	r10			# while (count > 0)
	jeql	.L2
	decl	r10			# count--
	movl	(r2),(r0)		# to = from
	cmpl	-(r2),-(r0)		# to--, from--
	jmp 	.L1
.L2:
.L_REST:
	movl	16(ap),r1		# r1 = is_new_child
	cmpl	$1,r1			# if is_new_child == 1
	jeql	.L6			# 	skip the copy-in loop
	#copy into target stack from to_run->t_savearea
	movl	12(ap),r11		# r11 = to_run
	movl	32(r11),r0		# r0 = to_run->t_basep (to)
	movl	36(r11),r10		# r10 = to_run->t_size (count)
		# Kick up the %sp if new stack will be taller than current.
	ashl	$2,r10,r2		# r2 = new stack height in bytes.
	subl3	r2,r0,r1		# r1 = target sp
	subl2	sp,r1			# r1 = r1 - sp
	cmpl	r1,$0			# if r1 < 0, kick up sp
	jgeq	.L3
	addl2	r1,sp
.L3:	movl	40(r11),r2		# r2 = to_run->t_savearea (from)
.L4:		# copy in loop
	tstl	r10			# while (count > 0)
	jeql	.L5
	decl	r10			# count--
	movl	(r2),(r0)		# to = from
	cmpl	-(r2),-(r0)		# --to, --from
	jmp 	.L4

.L5:		# restore state of to_run
	movl	20(r11),fp		# fp = to_run->t_framep
	# finally, delete to_run's t_savearea
	movl	36(r11),r1		# r1 = to_run->t_size
	ashl	$2,r1,r1		# scale size to bytes
	movl	40(r11),r2		# r2 = to_run->t_savearea
	subl2	r1,r2			# get low address of savearea
	addl2	$4,r2
	pushl	r2
	calls	$1,_swap_call_delete
	movl	$0,40(r11)		# to_run->t_savearea = 0
.L6:	ret
