#ifndef STACK1_C
#define STACK1_C
	// obsolete; should be replaced by gts_stack.c but string_to_graph still uses this
	// file.

#include "globals.h"
#include "global_registers.h"

	.align	4
	
	.data
	.align 4
stackTop:
	.long	0	
stackBottom:
	.long 	0
	// -----------------------------------------------------------------------------------
descStackTop:
	.long 0						// initialized at stackTop; is stack pointer
	
	.text
	.macro _pushl_descriptor_prefix2 dest
		// descStackTop points to last element
#ifdef COLOUR_GRAPH
		subl	$3,free					// free -= 3 (= 3 * 4 bytes)
#else			
		subl	$2,free					// free -= 2 (= 2 * 4 bytes)
#endif
		js		garbage_collection
		
		movl	descStackTop,\dest		// dest = descStackTop
#ifdef COLOUR_GRAPH
#define DESCRIPTOR1_PREFIX_ENTRY_SIZE 	16

#define	DPT1_PREFIX_SET_AND_STRING_PTR	0
#define DPT1_VIRTUAL_BASE				4
#define DPT1_LIBRARY_NUMBER				8
#define DPT1_DESCP_USAGE_SET_PTR			12


		subl	$ DESCRIPTOR_PR1EFIX_ENTRY_SIZE,\dest				// dest -= 8
#else
		subl	$8,\dest				// dest -= 8
#endif
		movl	\dest,descStackTop		// descStackTop -= 8	
	.endm

	// -----------------------------------------------------------------------------------
	
	.macro _pushl1 reg 					//label //gc
		cmpl	stackTop,stackP			// stackP > stackTop
		ja		0f						//jae 	\label
		
		subl	$1,free		 
		js 		garbage_collection		// \gc
		subl	$4,stackTop				// stackTop -= 4
	0:	
		subl 	$4,stackP				// stackP -= 4
		movl 	\reg,(stackP)				
	.endm
	
	// stack

	// copy of above; replaced garbage_collection by garbage_collection2
	.macro _pushl3 reg 					//label	//gc
		cmpl	stackTop,stackP			// stackP > stackTop
		ja		0f						//\label				//jae 	\label
		
		subl	$1,free
		js		garbage_collection2		// \gc
		subl	$4,stackTop				// stackTop -= 4
	0:	
		subl 	$4,stackP				// stackP -= 4
		movl 	\reg,(stackP)				
	.endm

	// _popl
	.macro _popl1 reg
		_popl_gc \reg garbage_collection
	.endm

	.macro _popl3 reg
		_popl_gc \reg garbage_collection2
	.endm

	.macro _popl_gc reg gc
		cmpl	stackBottom,stackP
		je	\gc
		
		movl	(stackP),\reg
		addl	$4,stackP
	.endm

	// _stack_empty
	.macro _stack_empty3 label
		_stack_empty \label
	.endm

	.macro _stack_empty label
		cmpl	stackBottom,stackP
		je 		\label
	.endm

	.macro N_reserve_stack_block t // l1 l2
		movl	stackP,\t
		subl	stackTop,\t				// temp = stackP - stackTop
		shrl	$2,\t
		
		cmpl	\t,arity				// arity < temp
		jbe		0f						// \l1	// enough space between stackTop and stackP
		
		// arity > temp
		// arity = arity - temp
		
		subl	\t,arity				// arity - available space between stackTop and stackP
		subl	arity,free				// free -= rest of arity			
		js		garbage_collection
		
		addl	\t,arity
		shll	$2,arity

		subl	arity,stackP			// stackP -= arity
		
		movl	stackP,stackTop
		shrl	$2,arity				// arity /= 4
		jmp		1f						//\l2
		
	0:		// \l1:
		movl	arity,\t	
		shll	$2,arity				// arity *= 4
		subl 	arity,stackP			//  reserve space between stackTop and stackP
		movl	\t,arity		
	1:		// \l2:
	.endm	

	/*
	** _copy_heap_block:
	**
	** call by:
	**
	** -	source
	**	the source address
	** -    arity
	**	number of longs to copy 	
	*/
	
	.macro _copy_heap_block
		
		subl 	arity,free			// free < length
		js 	garbage_collection
		
		cld
		rep
		movsl
	.endm

	/*
	** _copy_stack_block:
	**
	** call by:
	** -	source
	**	the source address
	** -    arity
	**	number of longs to copy
	** - 	t
	** 	temporary register
	** - 	l
	**	a globally unique label name
	**
	** result:
	** -	if possible arity * 4 longs of the stack have been reserved, containing
	** 	the longs stored at source; the first long is stored at the tos.
	*/
/*
	.macro N_copy_stack_block t l1 l2
		N_copy_stack_block_gc \t \l1 \l2 garbage_collection
	.endm
*/


	.macro N_copy_stack_block t // l1 l2
		
		/*
		** N_reserve_stack_block \t \l1 \l2
		*/
		movl	stackP,\t
		subl	stackTop,\t			// temp = stackP - stackTop
		shrl	$2,\t
	
		cmpl	\t,arity			// arity < temp
		jbe		0f					// \l1	// enough space between stackTop and stackP
		
		// arity > temp
		// arity = arity - temp
		subl	\t,arity			// arity - available space between stackTop and stackP
		subl	arity,free			// free -= rest of arity			
		js		garbage_collection
	
		addl	\t,arity
		shll	$2,arity

		subl	arity,stackP			// stackP -= arity
		movl	stackP,stackTop
		
//		subl	arity,stackTop			// stackTop -= arity
		shrl	$2,arity			// arity /= 4
		jmp		1f		// \l2
		
	0:			// \l1:
		movl	arity,\t	
		shll	$2,arity			// arity *= 4
		subl 	arity,stackP			//  reserve space between stackTop and stackP
		movl	\t,arity		
	1: 	//\l2:
		
		/*
		** Copy part
		*/
		
		movl	heapP,\t
		movl	stackP,heapP
		
		cld
		rep 
		movsl
		
		movl	\t,heapP
	.endm	

	// copy of the above; instead garbage_collection2 is called
	.macro N_copy_stack_block3 t //l1 l2
		
		/*
		** N_reserve_stack_block \t \l1 \l2
		*/
		movl	stackP,\t
		subl	stackTop,\t			// temp = stackP - stackTop
		shrl	$2,\t
	
		cmpl	\t,arity			// arity < temp
		jbe		0f					//\l1				// enough space between stackTop and stackP
		
		// arity > temp
		// arity = arity - temp
		
		subl	\t,arity			// arity - available space between stackTop and stackP
		subl	arity,free			// free -= rest of arity			
		js	garbage_collection2
	
		addl	\t,arity
		shll	$2,arity

		subl	arity,stackP			// stackP -= arity
		movl	stackP,stackTop
		
//		subl	arity,stackTop			// stackTop -= arity
		shrl	$2,arity			// arity /= 4
		jmp		1f 	//\l2
		
	0: 		// \L1:
		movl	arity,\t	
		shll	$2,arity			// arity *= 4
		subl 	arity,stackP			//  reserve space between stackTop and stackP
		movl	\t,arity		
	1:  //\l2:
		
	
		/*
		** Copy part
		*/
		
		movl	heapP,\t
		movl	stackP,heapP
		
		cld
		rep 
		movsl
		
		movl	\t,heapP
	.endm	


//#ifdef DYNAMIC_SUPPORT
	.macro _done //okdone
		cmpl	esp_backup,%esp
		je		0f  	// \okdone	
		ret
	0:   //\okdone:
	.endm
//#endif
	.macro _reserve_stack_block2 t
		cmpl	stackTop,stackP				// stackP <= stackTop
		jbe		garbage_collection2
		
		// stackP > stackTop
		movl	stackP,\t		
		subl	stackTop,\t					// free_stack_space = stackP - stackTop
		shrl	$2,\t						// free_stack_space in longs
		
		cmpl	\t,arity					// arity > free_stack_space
		ja		garbage_collection2			// out of memory, garbage collect
		
		// Enough space available
		movl	arity,\t		
		shll	$2,\t						// temp = arity * 4
		subl	\t,stackP					// stackP -= arity * 4	
	.endm

	.macro _copy_stack_block2 t
		cmpl	stackTop,stackP				// stackP <= stackTop
		jbe		garbage_collection2

		// stackP > stackTop
		movl	stackP,\t		
		subl	stackTop,\t					// free_stack_space = stackP - stackTop
		shrl	$2,\t						// free_stack_space in longs
		
		cmpl	\t,arity					// arity > free_stack_space
		ja		garbage_collection2			// out of memory, garbage collect
		
		// Enough space available, reserve stack memory
		movl	arity,\t		
		shll	$2,\t						// temp = arity * 4
		subl	\t,stackP					// stackP -= arity * 4
		
		// Copy to reserved memory area
		movl	heapP,\t					// backup heapP
		movl	stackP,heapP				// set destination		
		
		cld
		rep
		movsl
		
		movl	\t,heapP					// restore heapP
	.endm

//#ifdef zzz
	.macro	_pushl2 reg
/*
		cmpl	stackTop,stackP				// stackP <= stackTop
		jbe		garbage_collection2		
*/		
		subl	$4,stackP
		movl	\reg,(stackP)
	.endm
//#endif


// ------------------------------------------------------------------------------------------
// support for a moveable stack

// ecx = amount of bytes to move; preserves all registers except for status
	.align	4
	.text
	nop
	nop
	nop
	nop
	
move_stack_downwards:
#define n_bytes	%ecx
	pushl	%esi
	pushl	%edi
	pushl	%eax
	pushl	%ebx
	
#define newStackP	%eax
#define temp		%ebx
	movl	stackP,newStackP
	subl	n_bytes,newStackP			// newStackP = stackP - n_bytes
	pushl	newStackP
	
move_stack_loop:
	cmpl	stackP,stackBottom
	je 		move_stack_downwards2
	
	movl	(stackP),temp
	movl	temp,(newStackP)
	
	addl	$4,stackP
	addl	$4,newStackP
	
	jmp		move_stack_loop
	
move_stack_downwards2:
	popl	stackP

	movl	stackBottom,temp
	subl	n_bytes,temp				
	movl	temp,stackBottom			// stackBotom -= n_words
	
	movl	stackTop,temp
	subl	n_bytes,temp				
	movl	temp,stackTop				// stackTop -= n_words
#undef temp
#undef newStackP
	
	popl	%ebx
	popl	%eax
	popl	%edi
	popl	%esi

	ret
	nop
	nop
	nop
	nop
	nop
	nop
	
#undef n_bytes

#endif