/*
 * Copyright 2000, International Business Machines Corporation and others.
 * All Rights Reserved.
 * 
 * This software has been released under the terms of the IBM Public
 * License.  For details, see the LICENSE file in the top-level source
 * directory or online at http://www.openafs.org/dl/license10.html
 */

#ifdef AFS_HPUX_ENV
#ifdef hp9000s300
/*
#
#	Process assembly language assist for HP 9000 series 300s.
#
*/

	text

/*
#
# struct savearea {
#	char	*topstack;
# }
#
*/

	global	_PRE_Block

	set topstack,0

/* Stuff to allow saving/restoring registers */
	set NREGS,13
	set REGS,0x3ffe			# d1-d7 & a0-a5

/*
# savecontext(f, area1, newsp)
#     int (*f)(); struct savearea *area1; char *newsp;
*/

/* Stack offsets of arguments */
	set f,8
	set area1,12
	set newsp,16

	global	_savecontext
_savecontext:
	mov.b	&1,_PRE_Block		# Dont allow any interrupt finagling
	link	%a6,&-(NREGS*4)		# Save frame pointer & ...
					# ... allocate space for nregs registers
/* Save registers */
	movem.l	&REGS,(%sp)

	mov.l	area1(%a6),%a0		# a0 = base of savearea
	mov.l	%sp,topstack(%a0)	# area->topstack = sp
	mov.l	newsp(%a6),%d0		# Get new sp
	beq.b	l1			# If newsp == 0, no stack switch
	mov.l	%d0,%sp			# Switch to new stack
l1:
	mov.l	f(%a6),%a0		# a0 = f
	jsr	(%a0)			# f()

/* It is impossible to be here, so abort() */

	jsr	_abort

/*
# returnto(area2)
#     struct savearea *area2;
*/

/* Stack offset of argument */
set	area2,8

	global _returnto
_returnto:
	link	%a6,&0
	mov.l	area2(%a6),%a0		# Base of savearea
	mov.l	topstack(%a0),%sp	# Restore sp
/* Restore registers */
	movem.l	(%sp),&REGS

	add.l	&(NREGS*4),%sp
	mov.l	%sp,%a6			# Argghh...be careful here
	unlk	%a6
	clr.b	_PRE_Block
	rts				# Return to previous process
#else

	.CODE

	;
	; savecontext(f, area1, newsp)
	;    int (*f)();
	;    struct savearea *area1;
	;    char *newsp;
	;
savecontext
	.PROC
	;
	; Callinfo sets up register saves using the ENTRY_GR
	; and ENTRY_FR parameters.  ENTRY_FR=21 is only valid
	; for PA 1.1.  (How to deal with this for 800?)
	;
	.CALLINFO CALLER,FRAME=0,SAVE_RP,ENTRY_GR=18,ENTRY_FR=21
	; The ENTER statement generates register saves and
	; procedure setup.
	.ENTER

	LDI   1,%r31				; Store a (char) 1 in
	ADDIL LR'PRE_Block-$global$,%r27	; global variable
	STB   %r31,RR'PRE_Block-$global$(0,%r1)	; PRE_Block.

	COPY  %r26,%r22		; Copy arg0 (f) to dyncall's input register.

	COMIB,= 0,%r24,L$0001	; Compare arg2 (newsp) to 0.  Execute the
				; next instruction regardless of value.
	STWS  %r30,0(0,%r25)	; Store the stack pointer in the first
				; element (0th offset) of arg1 (area1).
	COPY  %r24,%r30		; Move arg2 (newsp) into the stack ptr.

L$0001
	.CALL
	BL    $$dyncall,%r31	; Dynamic call using pointer in r22.
	COPY  %r31,%r2

	.CALL
	BL    abort,%r2		; Can't get here, so abort.
	NOP
	.LEAVE
	.PROCEND

	; returnto(area2)
	;    struct savearea *area2;
	;
returnto
	.PROC
	.CALLINFO CALLER,FRAME=0,SAVE_RP,ENTRY_GR=18,ENTRY_FR=21
	;  No ENTRY is used since this is a magic routine.
	ADDIL LR'PRE_Block-$global$,%r27	; PRE_Block = 0
	STB   %r0,RR'PRE_Block-$global$(0,%r1)

	LDWS  0(0,%r26),%r30	; Load the stack pointer from area2
	.LEAVE
	.PROCEND

	.EXPORT savecontext,ENTRY
	.EXPORT returnto,ENTRY
	.IMPORT $global$,DATA
	.IMPORT PRE_Block,DATA
	.IMPORT $$dyncall,MILLICODE
	.IMPORT abort,CODE

	.END
#endif /* hp9000s300 */
#endif /* AFS_HPUX_ENV */
