	.file	"swap.s.3b"
#	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 and ap in running's t_framep and t_ap.
# 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 and t_ap to be the current fp and ap.
# If to_run is a new child, it explicitly restores the registers from
# New_task_regs, and returns with ret &0.
# If to_run is not a new child, it returns with ret &6.
# If running_task is TERMINATED, then we don't need to do a save.
	.text
	.globl swap
	.align	4
swap:
	save &6			# save all user regs (r3-r8)
	movw	4(%ap),%r2	# r2 = to_run
	movw	12(%ap),%r1	# r1 = running_is_terminated
	cmpw	&1,%r1		# if running is TERMINATED
	je	.L_RESTORE	# 	skip save
	movw	0(%ap),%r1	# r1 = running

	# save state of running task, unless it's TERMINATED
	movw	%fp,20(%r1)	# running->t_framep = fp
	movw	%ap,28(%r1)	# running->t_ap = ap
	movw	52(%r1),%r0	# r0 = running->t_mode
	cmpw	&2,%r0		# if running->t_mode == SHARED
	jne	.L_RESTORE
	# the code here to save the t_size is the same as for sswap
	subw3	32(%r1),%sp,%r0		# r0 = sp - running->t_basep (bytes)
	divw3	&4,%r0,36(%r1)		# running->t_size = r0 / 4 (int)

.L_RESTORE:
	movw	8(%ap), %r1	# r1 = is_new_child

	# restore state of to_run_task
	movw	20(%r2),%fp	# fp = to_run->t_framep
	movw	28(%r2),%ap	# ap = to_run->t_ap

	# if is_new_child, restore registers
	cmpw	&1,%r1
	je	.L_CHILD
	ret	&6		# not a new child

.L_CHILD:	# restore registers for new child
	# new child task effectively returns from task::task, so we need
	# to set the return value to "this"
	movw	24(%r2),%r0		# r0 = to_run->th
	movw	&New_task_regs,%r2
	movw	0(%r2),%r3
	movw	4(%r2),%r4
	movw	8(%r2),%r5
	movw	12(%r2),%r6
	movw	16(%r2),%r7
	movw	20(%r2),%r8
	ret &0

#	swap of SHARED
# sswap(*running, *prevOnStack, *to_run, is_new_child, running_is_terminated)
# This routine saves the fp and ap in running's t_framep and t_ap
# 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 and t_ap to be the current fp and ap.
# 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.
	.text
	.globl sswap
	.align	4
sswap:
	save &6				# save all user regs (r3-r8)
	movw	0(%ap),%r1		# r1 = running
	movw	4(%ap),%r4		# r4 = prevOnStack
	movw	16(%ap),%r0		# r0 = running_is_terminated
	cmpw	&1,%r0			# if running is TERMINATED
	je	.L_SKIP			# skip save
		#save hw state of running
	movw	%fp,20(%r1)		# running->t_framep = fp
	movw	%ap,28(%r1)		# running->t_ap = ap
	subw3	32(%r1),%sp,%r0		# r0 = sp - running->t_basep (bytes)
	divw3	&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
	cmpw	%r1,%r4			# if running == prevOnStack
	je	.L_REST			#	skip prevOnStack save

.L_SAVE:	#copy out target stack to prevOnStack->t_savearea
	movw	36(%r4),%r3		# r3 = prevOnStack->t_size (count)
	pushw	%r3
	call	&1,swap_call_new	# get count bytes of storage
	movw	%r0,40(%r4)		# prevOnStack->t_savearea = r0 (to)
	movw	32(%r4),%r2		# r2 = prevOnStack->t_basep (from)
.L1:		#copy out loop
	cmpw	%r3,&0			# while (count > 0)
	jle	.L2
	subw2	&1,%r3			# count--
	movw	0(%r2),0(%r0)		# to = from
	addw2	&4,%r2			# from++
	addw2	&4,%r0			# to++
	jmp	.L1
.L2:	
.L_REST:
	movw	12(%ap),%r1		# r1 = is_new_child
	cmpw	&1,%r1			# if is_new_child == 1
	je	.L6			# 	skip the copy-in loop
	#copy into target stack from to_run->t_savearea
	movw	8(%ap),%r4		# r4 = to_run
	movw	32(%r4),%r0		# r0 = to_run->t_basep (to)
	movw	36(%r4),%r3		# r3 = to_run->t_size (count)
	# Kick up the %sp if new stack will be taller than current.
	mulw3	&4,%r3,%r2		# r2 = new stack height in bytes.
	addw2	%r0,%r2			# r2 = target sp
	subw2	%sp,%r2			# r2 = r2 - sp
	cmpw	%r2,&0			# if r2 > 0, kick up sp
	jle	.L3
	addw2	%r2,%sp
.L3:	movw	40(%r4),%r2		# r2 = to_run->t_savearea (from)
.L4:		# copy in loop
	cmpw	%r3,&0			# while (count > 0)
	jle	.L5
	subw2	&1,%r3			# count--
	movw	0(%r2),0(%r0)		# to = from
	addw2	&4,%r2			# from++
	addw2	&4,%r0			# to++
	jmp 	.L4

.L5:		# restore hw state of to_run
	movw	20(%r4),%fp		# fp = to_run->t_framep
	movw	28(%r4),%ap		# to_run->t_ap
	# finally, delete to_run's t_savearea
	movw	40(%r4),%r2		# r2 = to_run->t_savearea
	pushw	%r2
	call	&1,swap_call_delete
	movw	&0,40(%r4)		# to_run->t_savearea = 0
.L6:	ret &6
