/* --- Copyright University of Sussex 1998. All rights reserved. ----------
 * File:            C.power/src/asignals.s
 * Purpose:
 * Author:          John Gibson, Mar 16 1998
 */

;;;------------------ POP CONDITION HANDLER ------------------------------

#_<

#_INCLUDE 'asm.ph'

section $-Sys;

constant
	procedure (Error_signal)
	;

vars
	Extern$- _invocation_fp
	;

endsection;

>_#

ASM_START_FILE


ASM_CODE_PSECT


;;; --- ROUTINE TO CLEAN UP AND CALL A POP ERROR HANDLER -----------------


ASM_NWRIT_PSECT
.globl __pop_errsig_adrtab
__pop_errsig_adrtab:
	.WORD	C_LAB(_special_var_block)
	.WORD	C_LAB(Sys$-Error_signal)


ASM_CODE_PSECT

	;;; Error signals set return to this.
	;;; Passed __pop_errsig_adrtab in rchain = R3
ASM_ALIGN_QUAD
.globl __pop_errsig
__pop_errsig:
	ldW	rsvb, _WOFFS*0(rchain)	;;; reset _special_var_block reg
	ldW	rfalse, _svb_FALSE	;;; set rfalse to false

	ldW	rt1, _svb_SAVED_SP	;;; get _saved_sp
	mr.	rt1, rt1
	bz	La1			;;; branch if not in external calls
	mr	rsp, rt1		;;; else remove stuff on system stack
	li	R0, 0
	stW	R0, _svb_SAVED_SP	;;; and clear _saved_sp
	INIT_POP_REGISTERS		;;; set pop lvar registers to false
	ldW	rusp, _SVB_OFFS(_userhi)(rsvb)	;;; reset user stack

La1:	ldW	rpb, _WOFFS*1(rchain)	;;; get Sys$-Error_signal
	b	XC_LAB(Sys$-Error_signal) ;;; call it


;;; --- SYSTEM CALLS --------------------------------------------------------

ASM_CODE_PSECT

	;;; _call_sys(______arg1, ..., ______argN, ___N, _________routine)
	;;; Call an external procedure, moving args from userstack to regs,
	;;; etc. No arg conversion and no callback -- for internal use only
	;;; (calls to this are generated by the _extern syntax form).
	;;; (User external calls are done in aextern.s)

ASM_ALIGN_QUAD
DEF_C_LAB (_call_sys)
	;;; save pop caller's stack frame ptr for exception conditions
	stW	rsp, _svb_SAVED_SP
	rlwinm	rsp, rsp, 0, ~0xf	;;; then quadword-align sp
	la	rsp, -_WOFFS*16(rsp)	;;; enough for quad-aligned tmp frame
	ldWu	rt0, _WOFFS(rusp)	;;; arg count ___N in rt0
	ldW	rpb, -_WOFFS(rusp)	;;; _________routine to call in rpb
	slwi	R0, rt0, _:WORD_SHIFT	;;; offset of args
	addic.	rt0, rt0, -8		;;; ___N - 8 for test
	add	rusp, rusp, R0		;;; address of last arg on stack
	stW	rusp, _svb_SAVED_USP	;;; save usp for after call

	;;; load argument registers (doesn't matter if there are less than 8)
	ldW	rt1, -_WOFFS*7(rusp)	;;; = R10
	ldW	rt2, -_WOFFS*6(rusp)
	ldW	rt3, -_WOFFS*5(rusp)
	ldW	rt4, -_WOFFS*4(rusp)
	ldW	rt5, -_WOFFS*3(rusp)
	ldW	rt6, -_WOFFS*2(rusp)
	ldW	rt7, -_WOFFS*1(rusp)	;;; = R4
	ldW	rchain, -_WOFFS*0(rusp)	;;; = R3

	bgt-	Lb2			;;; branch if more than 8 args

	;;; call the procedure
Lb1:	ldW	rt0, _svb_INVOC_FP	;;; frame pointer of pop's invoker
	ldW	R0, 0(rpb)		;;; exec address from descriptor
	stW	rtoc, _WOFFS*5(rsp)	;;; save TOC in standard frame
	stW	rt0, _WOFFS*0(rsp)	;;; and back chain to invocation frame
	mtctr	R0
	ldW	rtoc, _WOFFS(rpb)	;;; set TOC from descriptor
	ldW	rt0, _WOFFS*2(rpb)	;;; = R11 (is this necessary?)
	mflr	rfalse			;;; save my return in rfalse (AIX local)
	bctrl				;;; execute _________routine

	ldW	rtoc, _WOFFS*5(rsp)	;;; restore TOC from stack frame
	mtlr	rfalse			;;; restore my return
	ldW	rusp, _svb_SAVED_USP	;;; restore usp (args -1 removed)
	ldW	rfalse, _svb_FALSE	;;; restore rfalse
	li	R0, 0
	stW	rchain, 0(rusp)		;;; return result (= R3)
	ldW	rsp, _svb_SAVED_SP	;;; restore pop's sp
	stW	R0, _svb_SAVED_SP	;;; and zero _saved_sp
	ldW	rpb, _SF_OWNER(rsp)	;;; restore caller's pb
	blr				;;; return


	;;; more than 8 args
Lb2:	mtctr	rt0			;;; number of extra args -> count reg
	slwi	rt0, rt0, _:WORD_SHIFT	;;; offset of extra args
	addi	rt0, rt0, 0xf		;;; round up to quad mult
	rlwinm	rt0, rt0, 0, ~0xf
	subfc	rsp, rt0, rsp		;;; decr sp for extra args

	;;; copy remaining args to stack
	la	rt0, _WOFFS*13(rsp)	;;; where 8th arg goes on stack
	la	rusp, -_WOFFS*7(rusp)	;;; addr of 8th arg on userstack
Lb3:	ldWu	R0, -_WOFFS(rusp)	;;; get next arg
	stWu	R0, _WOFFS(rt0)		;;; store next arg
	bdnz-	Lb3			;;; loop if more

	b	Lb1			;;; call the procedure



ASM_END_FILE
