/* 
 * crt0.S: SDE-MIPS C runtime startup code.
 */

	
/*	
 * Includes additional initialisation for remote debug, fpa and timing.  
 * Also defined here is _exit().
 */
	
#include <mips/asm.h>
#include <mips/regdef.h>
#include <mips/cpu.h>
#include <sys/init.h>

	.sdata
EXPORTS(environ,4)
	.word	0
	
EXPORTS(_nofpu,4)
	.word	1		# initially no fpu support

IMPORT(_ram_based,4)

#if __mips64
#define	sr	sd
#define	lr	ld
#define rs	8
#else
#define	sr	sw
#define	lr	lw
#define rs	4
#endif

#if ! __mips64 || #abi(o32) || defined(__mips_algabi)
#define ARGSIZE			(4*4)
#else
#define ARGSIZE			(4*rs)
#endif
	
#define FRAMESIZE(nsave)	((ARGSIZE + ((nsave)*rs) + 7) & ~7)

#define topmem                  0x80200000        		
LEAF(__start)
	li      sp, topmem
	subu	sp,FRAMESIZE(1)
	sr	ra,ARGSIZE(sp)	# ra == 0 to terminate stack trace
	
	la	gp,_gp		# initialise $gp

	/* save argc, argv, and environ for main() */
	move	s0,a0
	move	s1,a1
	sw	a2,environ

        .set noreorder
	/* clear bss */
	la	a0,_fbss
	la	a2,_end
1:
        beq     a2, a0, 2f      
	nop                     /* branch slot */
        sw      zero, 0(a2)  
	beq     zero, zero, 1b
        addiu   a2, -4          /* branch slot */
        .set reorder

2:              	
	/* rv = main(argc, argv, environ) */
	move	a0,s0
	move	a1,s1
	lw	a2,environ
	jal	main

	/* exit(rv) */

        move	a0,v0
#if 0        
#ifdef MINKIT	
	jal	_exit
#else	
	jal	exit
#endif
#endif	
	/* just in case !! */
1:	break	1
	b	1b
	j	ra			# end of subroutine marker
END(__start)

#if 0	
WLEAF(_exit)
XLEAF(_quit)	
	subu	sp,FRAMESIZE(2)
	sr	s2,ARGSIZE(sp)	
	sr	ra,ARGSIZE+rs(sp)	# only for stack trace

	move	s2,a0		# save _exit argument

#ifdef MINKIT	
	/* Call C++ global destructors on _exit() - in non-MINKIT
	   case this is done via atexit(). */
	jal	_do_global_dtors
#endif
	
#ifndef MINKIT	
#ifdef TIMING
	jal	clock		# get total clock time
	la	a0,1f
	.rdata
1:	.asciiz	"\nElapsed time: %d.%06d seconds\n"
	.text
	divu	a1,v0,1000000	# a1 = quotient  (seconds)
	mfhi	a2		# a2 = remainder (micro seconds)
	jal	_mon_printf	# print time message
#endif

	/* Close down run-time i/o system */
	jal	_call_fini_funcs
#endif /* !MINKIT */

#if RDBG > 0
	/* tell remote debugger that program has exited */
	move	a0,s2		# restore _exit status argument
	jal	_debug_exit	
#endif
		
	move	a0,s2		# restore _exit status argument
	la	ra,__exit	# really, really exit!
	jr	ra		# end of function
END(_exit)
	

/* dummy __main for Cygnus tools */
WLEAF(__main)
	j	ra
WEND(__main)
	
/* For C++ exception handling, bigger than necessary, but safe */	
LBSS(__main_object, 64)

/* dummy frame unwinding info handling when not C++ */
WLEAF(__register_frame_info)
	j	ra
WEND(__register_frame_info)
	
WLEAF(__register_frame_info_table)
	j	ra
WEND(__register_frame_info_table)
	
WLEAF(__deregister_frame_info)
	j	ra
WEND(__deregister_frame_info)
	
WLEAF(__deregister_frame_info_table)
	j	ra
WEND(__deregister_frame_info_table)
	
#ifndef MINKIT
/* dummy weak version of sig_raise(pgrp, sig, xcp) */
WLEAF(_sig_raise)
	sll	s0,a1,8
	beqz	a2,1f
	move	a0,a2
	jal	xcpt_show
1:	move	a0,s0
	la	ra,_exit
	j	ra
WEND(_sig_raise)
#endif
	

/*
 * Call each function in the .sdeinit list
 */
LEAF(_call_init_funcs)
	subu	sp,FRAMESIZE(3)
	sr	s0,ARGSIZE(sp)
	sr	s1,ARGSIZE+rs(sp)
	sr	ra,ARGSIZE+rs+rs(sp)

	la	s0,__SDEINIT_LIST__
	move	s1,a0
1:	lw	t0,0(s0)
	lw	t1,4(s0)
	addu	s0,8		# bump pointer
	beqz	t0,2f		# end of table
	bne	t0,s1,1b	# no match - get next
	jal	t1		# match - call function
	b	1b

2:	lr	ra,ARGSIZE+rs+rs(sp)
	lr	s1,ARGSIZE+rs(sp)
	lr	s0,ARGSIZE(sp)
	addu	sp,FRAMESIZE(3)
	j	ra
END(_call_init_funcs)
	

/*
 * Call each function in the C++ global constructor list, in
 * reverse order.
 */
SLEAF(_do_global_ctors)
	subu	sp,FRAMESIZE(3)
	sr	s0,ARGSIZE(sp)
	sr	s1,ARGSIZE+rs(sp)
	sr	ra,ARGSIZE+rs+rs(sp)

	la	s0,__CTOR_LIST__+4
	move	s1,s0
	
	/* get constructor count */
	lw	t0,-4(s1)
	bltz	t0,1f
		
	/* +ve value in count, add to pointer */
	sll	t0,2
	addu	s1,t0
	b	4f
	
	/* -ve value in count, search for null terminator */
1:	lw	t0,0(s1)
	addu	s1,4
	beqz	t0,3f
	b	1b

	/* call constructors in reverse order */
2:	lw	t0,-4(s1)
	jal	t0
3:	subu	s1,4
4:	bne	s0,s1,2b

	lr	ra,ARGSIZE+rs+rs(sp)
	lr	s1,ARGSIZE+rs(sp)
	lr	s0,ARGSIZE(sp)
	addu	sp,FRAMESIZE(3)
	j	ra
SEND(_do_global_ctors)

	
/*
 * Call each function in the C++ global destructor list, in forward order
 */
SLEAF(_do_global_dtors)
	subu	sp,FRAMESIZE(2)
	sr	s0,ARGSIZE(sp)
	sr	ra,ARGSIZE+rs(sp)

	/* call destructors in forward order */
	la	s0,__DTOR_LIST__+4
1:	lw	t0,0(s0)
	addu	s0,4
	beqz	t0,2f
	jal	t0
	b	1b

	/* call .fini section */
2:	jal	__fini
	
	/* tear down C++ exception handling */
	la	a0,__EH_FRAME_BEGIN__
	jal	__deregister_frame_info
	
	lr	ra,ARGSIZE+rs(sp)
	lr	s0,ARGSIZE(sp)
	addu	sp,FRAMESIZE(2)
	j	ra
SEND(_do_global_dtors)
	

/*
 * Start the C++ global constructor/destructor lists.
 * First entry is number of pointers, or -1 if unknown.
 * The lists are always null-terminated (by crtn.o).
 */
	.section .ctors,"a",@progbits
	.align	2
.globl __CTOR_LIST__
__CTOR_LIST__:
	.word	-1

	.section .dtors,"a",@progbits
	.align	2
.globl __DTOR_LIST__
__DTOR_LIST__:
	.word	-1
	
	.section .eh_frame,"a",@progbits
__EH_FRAME_BEGIN__:

/*
 * Start the SDE run-time system global initialisation/finish lists.
 */

	.section .sdeinit,"a",@progbits
	.align	2
.globl __SDEINIT_LIST__
__SDEINIT_LIST__:
	
	.section .sdefini,"a",@progbits
	.align	2
.globl __SDEFINI_LIST__
__SDEFINI_LIST__:
	
/*
 * Start the C .init/.fini sections, which contain a set of 
 * instructions.
 */
	
	.section .init,"ax",@progbits
	.globl	__init
	.ent __init
	.align 2
__init:
	subu	sp,FRAMESIZE(1)
	sr	ra,ARGSIZE(sp)
	.end __init
		
	.section .fini,"ax",@progbits
	.globl __fini
	.ent __fini
	.align 2
__fini:
	subu	sp,FRAMESIZE(1)
	sr	ra,ARGSIZE(sp)
	.end __fini

	
/*
 * Force a list of run-time "features" to be loaded.
 */
	.rdata	
featuretab:	
#ifndef MINKIT
	.word	_ttydev_load		/* /dev/tty interface */
#endif	
#ifdef FEATURES
	.word	FEATURES
#endif	
	.word	0
#endif


