/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/* Copyright (c) 1996 NeXT Software, Inc.  All rights reserved.
 *
 *	File:	architecture/ppc/asm_help.h
 *	Author:	Mike DeMoney, NeXT Software, Inc.
 *
 *	This header file defines macros useful when writing assembly code
 *	for the PowerPC processors.
 *	r12 is used as the tmp register / PICIFY base.
 *
 * HISTORY
 * 20-May-97  Umesh Vaishampayan (umeshv@apple.com)
 *	Implemented Dynamic / PIC macros.
 *
 * 28-Dec-96  Umesh Vaishampayan (umeshv@NeXT.com)
 *	added ".align" directive to various macros to avoid alignment 
 *  	faults. Moved Register Usage #defines to reg_help.h as that's
 *	where they should have been in the first place.
 *	Added Dynamic / PIC macroes for routines which refernce external
 *	symbols. Not implemented fully as yet.
 *
 * 05-Nov-92  Mike DeMoney (mike@next.com)
 *	Created.
 */

#ifndef	_ARCH_PPC_ASM_HELP_H_
#define	_ARCH_PPC_ASM_HELP_H_

#include	<architecture/ppc/reg_help.h>

#ifdef	__ASSEMBLER__
/*
 * ppc stack frames look like this after procedure prolog has
 * been executed:
 *
 * Higher address:
 *			.........
 *		+-------------------------------+
 * 		| caller's LR			|
 *		+-------------------------------+
 * 		| caller's CR			|
 *		+-------------------------------+
 * Caller's SP->| caller's caller's sp		|  ^^ Caller's Frame ^^
 *		+===============================+  vv Called Rtn Frame vv
 *		|	Save Area for		| FPF 31
 *			..........
 *		| 	Caller's FPF's		| FPF n
 *		+-------------------------------+
 *		|	Save Area for		| GRF 31
 *			..........
 *		| 	Caller's GRF's		| GRF n
 *		+-------------------------------+
 *		|	alignment pad		|
 *			............
 *		|	(if necessary)		|
 *		+-------------------------------+
 *		|	Local			|
 *			........
 *		| 	Variables		|
 *		+-------------------------------+
 * SP + X ->	| aN for FUTURE call		|
 *		+-------------------------------+
 *			..........
 *		+-------------------------------+
 * SP + 28 ->	| a1 for FUTURE call		|
 *		+-------------------------------+
 * SP + 24 ->	| a0 for FUTURE call		|
 *		+-------------------------------+
 * SP + 20 ->	| caller's TOC			|
 *		+-------------------------------+
 * SP + 16 ->	| reserved			|
 *		+-------------------------------+
 * SP + 12 ->	| reserved			|
 *		+-------------------------------+
 * SP + 8 ->	| LR callee-save for FUTURE call|
 *		+-------------------------------+
 * SP + 4 ->	| CR callee-save for FUTURE call|
 *		+-------------------------------+
 * SP ->	| caller's sp			|
 *		+===============================+
 * Lower address:
 *
 * NOTE: All state with the exception of LR and CR are saved in the
 * called routines frame.  LR and CR are saved in the CALLER'S FRAME.
 *
 * ALSO NOTE: Args to the called routine are found in the caller's frame.
 */

/*
 * ARG(n) -- stack offset to n'th argument
 *
 * NOTE CAREFULLY!  These macros start numbering arguments at 1 (NOT 0)
 * The first argument is ARG(1).
 *
 * ALSO NOTE:  This stack offset is only valid if using routine
 * DOES NOT alter SP.
 *
 */
#define	ARG(n)		((((n) - 1) * 4) + 24)

/*
 * Macros for building stack frame according to C calling conventions.
 * lr, cr, and sp are saved.
 *
 * NOTE WELL: localvarsize is in bytes, maxargsout is a count of words,
 * grfsaved and fpfsaved is a count of registers.  BE SURE TO COUNT
 * BOTH FP (r31) AND sN REGISTERS IN THE COUNT OF GRF REGISTERS SAVED!
 * This will be TWO more than the N of the highest sN register you
 * save: s2 implies you are saving s2, s1, s0, and fp => grfsaved
 * should be 4!
 *
 * FURTHER NOTE: These macros do NOT SAVE GRF or FPF registers.  User
 * must do that.  GRF sN regs should be saved via
 *	stmw	sN,SAVED_GRF_S(N)(sp)
 * where N is the highest numbered s* register to be saved.  E.g. if
 * s0, s1, and s2 are to be saved use:
 *	stmw	s2,SAVED_GRF_S(2)(sp)
 * Note that this also saves fp.
 * An individual saved grf can be loaded via:
 *	lwz	s2,SAVED_GRF_S(2)(sp)
 * Analogous stuff works for fpf's.
 *
 * NOTE: these simple routines will be replaced with more complicated
 * ones once we know what the linker and gdb will require as for as 
 * register use masks and frame declarations.
 *
 * Warning: ROUND_TO_STACK is only to be used in assembly language;
 * for C usage, use ROUND_FRAME() in reg_help.h.
 */
#define	ROUND_TO_STACK(len)				\
	(((len) + STACK_INCR - 1) / STACK_INCR * STACK_INCR)

#define	BUILD_FRAME(localvarsize, maxargsout, grfsaved, fpfsaved)	\
	.set	__argoutsize, ROUND_TO_STACK((maxargsout) * 4)		@\
	.if	__argoutsize < 32					@\
	  .set	__argoutsize,32						@\
	.endif								@\
	.set	__framesize, ROUND_TO_STACK(				\
			24 + __argoutsize + (localvarsize)		\
			+ 4*(grfsaved) + 8*(fpfsaved))			@\
	.set	__grfbase,(__framesize - 4*(grfsaved) - 8*(fpfsaved))	@\
	.set	__fpfbase,(__framesize - 8*(fpfsaved))			@\
	mflr	r0							@\
	mfcr	r12							@\
	stw	r0,8(sp)						@\
	stw	r12,4(sp)						@\
	stwu	r1,-__framesize(r1)

/*
 * Macros for referencing data in stack frame.
 *
 * NOTE WELL: ARG's and VAR's start at 1, NOT 0. Why ??? (FIXME)
 */
#define	LOCAL_VAR(n)	(((n)-1)*4 + __argoutsize + 24)
#define	SAVED_GRF_S(n)	(__grfbase + ((grfsaved) - (n) - 2) * 4)
#define	SAVED_FRF_FS(n)	(__fpfbase + ((fpfsaved) - (n) - 1) * 4)
#define	ARG_IN(n)	(ARG(n) + __framesize)
#define	ARG_OUT(n)	(ARG(n) + 0)
#define	SAVED_FP	(__grfbase + ((grfsaved) - 1) * 4)
#define	SAVED_LR	(__framesize + 8)
#define	SAVED_CR	(__framesize + 4)

/*
 * Macros for unwinding stack frame.
 * NOTE: GRF's and FPF's are NOT RESTORED.  User must do this before
 * using this macro.
 */
#define	RETURN						\
	.if	__framesize				@\
	  lwz32	r0,r1,SAVED_LR				@\
	  lwz32	r12,r1,SAVED_CR				@\
	  addic	sp,r1,__framesize			@\
	  mtlr	r0					@\
	  mtcrf	0xff,r12				@\
	  blr						@\
	.else						@\
	  blr						@\
	.endif


/*
 * Macros for declaring procedures
 *
 * Use of these macros allows ctags to have a predictable way
 * to find various types of declarations.  They also simplify
 * inserting appropriate symbol table information.
 *
 * NOTE: these simple stubs will be replaced with more
 * complicated versions once we know what the linker and gdb
 * will require as far as register use masks and frame declarations.
 * These macros may also be ifdef'ed in the future to contain profiling
 * code.
 *
 * FIXME: Document what makes a leaf a LEAF and a handler a HANDLER.
 * (E.g. leaf's have return pc in lr, NESTED's have rpc in offset off
 * sp, handlers have rpc in exception frame which is found via exception
 * link, etc etc.)
 */

/*
 * TEXT -- declare start of text segment
 */
#define	TEXT						\
	.text						@\
	.align 2

/*
 * LEAF -- declare global leaf procedure
 * NOTE: Control SHOULD NOT FLOW into a LEAF!  A LEAF should only
 * be jumped to.  (A leaf may do an align.)  Use a LABEL() if you
 * need control to flow into the label.
 */
#define	LEAF(name)					\
	.align 2					@\
	.globl	name					@\
name:							@\
	.set	__framesize,0

/*
 * X_LEAF -- declare alternate global label for leaf
 */
#define	X_LEAF(name, value)				\
	.globl	name					@\
	.set	name,value

/*
 * P_LEAF -- declare private leaf procedure
 */
#define	P_LEAF(name)					\
	.align 2					@\
name:							@\
	.set	__framesize,0

/*
 * LABEL -- declare a global code label
 * MUST be used (rather than LEAF, NESTED, etc) if control
 * "flows into" the label.
 */
#define	LABEL(name)					\
	.align 2					@\
	.globl	name					@\
name:

/*
 * NESTED -- declare procedure that invokes other procedures
 */
#define	NESTED(name, localvarsize, maxargsout, grfsaved, fpfsaved)\
	.align 2				@\
	.globl	name				@\
name:						@\
	BUILD_FRAME(localvarsize, maxargsout, grfsaved, fpfsaved)

/*
 * X_NESTED -- declare alternate global label for nested proc
 */
#define	X_NESTED(name, value)			\
	.globl	name				@\
	.set	name,value

/*
 * P_NESTED -- declare private nested procedure
 */
#define	P_NESTED(name, localvarsize, maxargsout, grfsaved, fpfsaved)\
	.align 2					@\
name:							@\
	BUILD_FRAME(locavarsize, maxargsout, grfsaved, fpfsaved)

/*
 * HANDLER -- declare procedure with exception frame rather than
 * standard C frame
 */
#define	HANDLER(name)					\
	.align 2					@\
	.globl	name					@\
name:

/*
 * X_HANDLER -- declare alternate name for exception handler
 * (Should appear immediately before a HANDLER declaration or
 * another X_HANDLER declaration)
 */
#define	X_HANDLER(name)					\
	.align 2					@\
	.globl	name					@\
name:

/*
 * P_HANDLER -- declare private handler
 */
#define	P_HANDLER(name)					\
	.align 2				@\
name:

/*
 * END -- mark end of procedure
 * FIXME: Unimplemented for now.
 */
#define	END(name)

/*
 * BL -- call procedure (relative)
 */
#define	BL(name)					\
	bl	name

/*
 * Storage definition macros
 * The main purpose of these is to allow an easy handle for ctags
 */

/*
 * IMPORT -- import symbol
 */
#define	IMPORT(name)					\
	.reference	name

/*
 * ABS -- declare global absolute symbol
 */
#define	ABS(name, value)				\
	.globl	name					@\
	.set	name,value

/*
 * P_ABS -- declare private absolute symbol
 */
#define	P_ABS(name, value)				\
	.set	name,value

/*
 * EXPORT -- declare global label for data
 */
#define	EXPORT(name)					\
	.align 2					@\
	.globl	name					@\
name:

/*
 * BSS -- declare global zero'ed storage
 */
#define	BSS(name,size)					\
	.comm	name,size


/*
 * P_BSS -- declare private zero'ed storage
 */
#define	P_BSS(name,size)				\
	.lcomm	name,size

/*
 * dynamic/PIC macros for routines which reference external symbols
 */
#if defined(__DYNAMIC__)
#define PICIFY_REG r12

/* Assume that the lr is saved before calling any of these macros */
/* using PICIFY() */

#define PICIFY(var)				\
	mflr	r0				@\
	bl	1f				@\
1:	mflr	PICIFY_REG			@\
	mtlr	r0				@\
	addis	PICIFY_REG, PICIFY_REG, ha16(L ## var ## $non_lazy_ptr - 1b) @\
	lwz	PICIFY_REG, lo16(L ## var ## $non_lazy_ptr - 1b)(PICIFY_REG)

#define CALL_EXTERN_AGAIN(var)			\
	PICIFY(var)				@\
	mtctr	PICIFY_REG			@\
	mflr	r0				@\
	stw	r0,8(r1)			@\
	stwu	r1,-56(r1)			@\
	bctrl					@\
	addic	r1,r1,56     			@\
	lwz	r0,8(r1)			@\
	mtlr	r0

#define NON_LAZY_STUB(var)			\
	.non_lazy_symbol_pointer		@\
	.align 2				@\
L ## var ## $non_lazy_ptr:			@\
	.indirect_symbol var			@\
	.long 0					@\
	.text					@\
	.align 2

#define	BRANCH_EXTERN(var)			\
	PICIFY(var)				@\
	mtctr	PICIFY_REG			@\
	bctr					@\
	NON_LAZY_STUB(var)

#define CALL_EXTERN(var)			\
	CALL_EXTERN_AGAIN(var)			@\
	NON_LAZY_STUB(var)

#define REG_TO_EXTERN(reg, var)			\
	PICIFY(var)				@\
	stw reg, 0(PICIFY_REG)			@\
	NON_LAZY_STUB(var)

#define EXTERN_TO_REG(reg, var)			\
	PICIFY(var)				@\
	lwz	reg, 0(PICIFY_REG)		@\
	NON_LAZY_STUB(var)

#else /* ! __DYNAMIC__ */
#define TMP_REG r12
#define BRANCH_EXTERN(var)			\
	b	var

#define CALL_EXTERN(var)			\
	bl	var

#define CALL_EXTERN_AGAIN(var)			\
	CALL_EXTERN(var)

#define REG_TO_EXTERN(reg, var)			\
	lis	TMP_REG, ha16(var)		@\
	stw	reg, lo16(var)(TMP_REG)

#define EXTERN_TO_REG(reg, var)			\
	lis	reg, ha16(var)			@\
	lwz	reg, lo16(var)(reg)

#endif	/* __DYNAMIC__ */

#endif	/* __ASSEMBLER__ */
#endif	/* _ARCH_PPC_ASM_HELP_H_ */
