/*
 * $Header: /smsa/bsd:include/arm/as_support.h:bsd  1.8  $
 * $Source: /smsa/bsd:include/arm/as_support.h: $
 *
 * Copyright (c) 1988 Acorn Computers Ltd., Cambridge, England
 *
 */
#ifndef __arm_as_support_h
#define __arm_as_support_h
#define	__machine_as_support_h	"arm"

/*
 *	Support for assembler library routines.  This include
 *	file is designed for use with cpp on as source code (NOT
 *	C source code!)
 *
 *	The following options are supported:-
 *
 *	PROF -	If defined produce procedure entries with support
 *		for prof or gprof profiling.
 *	NAME -	If defined produce procedure name headers before
 *		the entry point for use in procedure backtrace.
 * 
 */

#ifndef	__sys_syscall_h
#include "../sys/syscall.h"
#endif
#ifndef	__arm_trap_h
#include "trap.h"
#endif
#ifndef __arm_apcs_h
#include "apcs.h"
#endif
#ifndef	__sys_errno_h
#include "../sys/errno.h"
#endif

/*
 * HEADER -	Inserts a procedure header, no effect if NAME is
 *		not defined.  Always forces alignment to a word
 *		boundary.
 * _ENTRY -	Produce a procedure header and entry point, the
 *		header and entry point are named separately
 *		allowing production of multiple entry points for
 *		procedure aliases, or of assembler entry points
 *		(without the leading ``_'').  The entry point is
 *		NOT declared as a global symbol.
 * ENTRY  -	Produce a procedure entry, complete with header
 *		and profiling code if required.  The parameter
 *		is the name of the function WITHOUT the leading
 *		_ required to access it from C.
 * ENTRY2 -	Produce an entry point and an alias for this -
 *		the procedure header is for the first named
 *		procedure, the alias is used as an extra name.
 * OENTRY -	Produce an entry point for an out-of-line operator
 *		or other assembler procedure - no leading _ is
 *		prepended.
 *
 * These macros define local labels under some circumstances -
 * do not rely on local labels across these macros.
 *
 * UNIXSWI -	Constructs the relevant swi instruction for the
 *		kernel entry given by its parameter.  These are
 *		as defined by <sys/syscall.h> (without the leading
 *		SYS_).
 *
 * SYSCALL -	Defines the first part of a procedure corresponding
 *		to the kernel entry named in the parameter (including
 *		the error handling section).
 *
 * PSEUDO -	As SYSCALL except the first paramter names the function
 *		and the second the corresponding SWI.  No error check
 *		is done.
 *
 * CALL -	Calls the C function passed as a parameter (a leading
 *		``_'' is added).
 *
 * RET -	Compiles a return instruction (from a leaf procedure -
 *		ie the return address must be in lr).  Also compiles
 *		a .pool directive (so this can only be used at the
 *		end of the function).
 *
 * CPROC -	Generates the entry sequence for the given function.
 *		This macro must be followed immediately by the list of
 *		v? registers which are to be saved on entry to the 
 *		routine, for example:-
 *
 *			CPROC(printf)	{v1, v2, v5}
 *
 *		Suitable code will be compiled to produce the required
 *		stack frame.  The CRET macro must be used to 
 *		return from such a procedure.  If argument registers need
 *		to be stored use the following macro.  None of these macros
 *		will handle fp registers correctly.
 *
 * CVPROC -	varargs type C routine which saves its argument registers
 *		on the stack first.
 *
 * CRET -	Return from the named procedure, reloading the appropriate
 *		registers.
 *
 * CLOAD -	Load up the saved registers from the stack frame - suitable
 *		for use in tail recursion elimination from a CPROC procedure.
 *
 * ASTUB -	Compiles a stub for the function named in its paramter
 *		which simply indicates that the desired function is
 *		not written (on the error stream) and returns a 
 *		failure code.
 */

#ifdef NAME
#	define HEADER(x)		\
		.text;			\
		.align	0;		\
	2:	.asciz	"x";		\
		.word	0xff000000+.-2b;
#else
#	define HEADER(x)		\
		.text;			\
		.align	0;
#endif

/*
 * _ENTRY is the fundamental operation.
 */
#ifdef PROF
#	define	_ENTRY(x,y)		\
		.bss;			\
	1:	.space 4;		\
		HEADER(y)		\
	x:	mov	ip, lr;		\
		.globl	mcount;		\
		bl	mcount;		\
		.word	1b;
#else
#	define	_ENTRY(x,y)		\
		HEADER(y)		\
	x:
#endif PROF

#	define	ENTRY(x)		\
		.globl	_/**/x;		\
		_ENTRY(_/**/x,x)

#	define	ENTRY2(x,y)		\
		.globl	_/**/x;		\
		.globl	_/**/y;		\
		_ENTRY(_/**/x:_/**/y,x)

#	define	OENTRY(x)		\
		.globl	x;		\
		_ENTRY(x,x)

#	define	UNIXSWI(x)		\
		swi	SWI_OS_UNIX | SYS_/**/x;

#	define	SYSCALL(x)		\
		ENTRY(x)		\
		UNIXSWI(x)		\
		.globl	cerror;		\
		bcs	cerror;

#	define	PSEUDO(x,y)		\
		ENTRY(x)		\
		UNIXSWI(y)

#	define	CALL(x,y)		\
		bl	_/**/y;

#	define	RET			\
		movs	pc, lr;		\
		.pool;

/*
 * CPROC is followed immediately (on the same line) by the
 * relevant register list - hence the unfinished statement
 * at the end.
 */
#	define CPROC(func)							\
		ENTRY(func)						\
		mov	ip, sp;						\
		stmfd	sp!, L.func.saved.regs | {fp, ip, lr, pc}; 	\
		sub	fp, ip, #4;					\
	L.func.saved.regs	.equ	

#	define CVPROC(func)						\
		ENTRY(func)						\
		mov	ip, sp;						\
		stmfd	sp!, {a1, a2, a3, a4};				\
		stmfd	sp!, L.func.saved.regs | {fp, ip, lr, pc}; 	\
		sub	fp, ip, #4;					\
	L.func.saved.regs	.equ	

#	define	CRET(func)							\
		ldmdb	fp, L.func.saved.regs | {fp, sp, pc}^;

#	define	CLOAD(func)							\
		ldmdb	fp, L.func.saved.regs | {fp, sp, lr};

/*
 * ASTUB always exits via cerror - if there is an error
 * in the write it returns that, else it returns EINVAL
 * to errno.
 */
#	define	ASTUB(func) 			\
		ENTRY(func)			\
		mov	a1, #2			\
		adr	a2, 0f;			\
		mov	a3, #1f-0f;		\
		UNIXSWI(write)			\
		movcc	a1, #EINVAL		\
		.globl	cerror;			\
		b	cerror;			\
	0:	.ascii	"func: not implemented\n";\
	1:	;

#endif/*__arm_as_support_h*/

/* EOF as_support.h */
