/* (C) Copyright IBM Corp. 2005, 2006
All rights reserved.

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, 
this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright 
notice, this list of conditions and the following disclaimer in the 
documentation and/or other materials provided with the distribution.
    * Neither the name of IBM nor the names of its contributors may be 
used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

/* crt0.S - entry function for C Runtime.
 *
 * With _STD_MAIN switch, the crt0.S will be compiled to crt2.o.
 * The crt2.o sets up a C99-style interface for the SPU application's
 * main() function, including a local copy of argv strings.
 * 
 * The number of argument strings is passed in R3.  The size and EA 
 * location of the argument vector region is passed in R4.  Once the
 * argv region is copied to the highest range of LS, and $SP is set 
 * just below it.
 *
 * Without _STD_MAIN, the crt0.S is compiled to crt1.o. 
 * The crt1.o prepares the entry for an SPU module. The main() function
 * is called with different parameter list: spu_id, param and env 
 * are passed by R3, R4 and R5 respectively.
 */

#ifdef _STD_MAIN
#define MFC_TAG_UPDATE_ALL 	2
#define MFC_GET_CMD		0x40
#define TAGID			0
#define TAGMASK			1
#endif

.comm __ea_local_store,16,16

.text
.global _start
.type _start, @function
	
_start:
	/* Save the local store base from $6.  */
	stqr $6, __ea_local_store

#ifdef _STD_MAIN
	/* 
 	 * Copy the argument vector region from EA to LS.  The DMA
	 * parameters are passed in R4:
	 *
 	 *        +-------+-------+-------+-------+
	 *     R4 |   LS  | EA-HI | EA-LO | SIZE  |
	 *        +-------+-------+-------+-------+
	 *  word     0       1       2       3
	 *
 	 * By the end of this sequence, the prefered slot (word 0) of
	 * R4 will contain the LS offset of argv region, which also
	 * serves as the base offset for $SP.
	 */
	wrch	$MFC_LSA, $4
	rotqbyi	$4, $4, 4
	wrch	$MFC_EAH, $4
	rotqbyi	$4, $4, 4
	wrch	$MFC_EAL, $4
	rotqbyi	$4, $4, 4
	wrch	$MFC_Size, $4
	rotqbyi	$4, $4, 4
	il	$LR, TAGID
	wrch	$MFC_TagID, $LR

	/* Issue MFC_GET_CMD, then wait for transfer of argument
	 * vector region to complete.
	 */
	il	$LR, MFC_GET_CMD
	wrch	$MFC_Cmd, $LR
	il	$LR, TAGMASK
	wrch	$MFC_WrTagMask, $LR
	il	$LR, MFC_TAG_UPDATE_ALL
	wrch	$MFC_WrTagUpdate, $LR
	rdch	$LR, $MFC_RdTagStat
#endif

	/* Save parameter list of main function to the non-volatile
	 * registers. spu_thread module has three parameters, while
	 * spulet only has two.
	 */
	ori     $80, $3, 0
	ori     $81, $4, 0
#ifndef _STD_MAIN
	ori 	$82, $5, 0
#endif

	/* The Link Register is initialized to NULL.
	 */
	il	$LR, 0

#ifdef _STD_MAIN	
	/* For spulet, initialize stack pointer just below the argv region.
	 */
	ai	$SP,$4,-16
#else
	/* For spe_thread module, the stack pointer is initialized 
	 * below the area where __stack points to.
	 */
	ila     $SP,__stack
#endif
	/* Initialize back chain to NULL.
	 */
	stqd    $LR,0($SP)

	/* Allocate 2 slots for stack frame.
	 */
	stqd    $SP,-32($SP)
	ai      $SP,$SP,-32

	/* Save the Link Register in Link Register Save Area.
	 */
	stqd	$LR,16($SP)

	/* Calculate stack size.
	 */
	ila 	$3,_end
	sf	$3,$3,$SP
	rotqbyi	$3,$3,12

        /* The BE Linux ABI passes the stack size in $2, or use
         * the default if $2 == 0.
         */
	rotqbyi	$4,$2,12
	ceqi	$5,$4,0
	selb	$3,$4,$3,$5
	fsmbi	$4,3840
	selb	$SP,$SP,$3,$4

	/* Call the _init function.
	 */
	brsl	$LR, _init
	
	/* Call the _fini function at exit time.
	 */
	ila	$3, _fini
	brsl	$LR, atexit

#ifdef _PROFILE
	/* Call monstartup if profiling is enabled
	 */
#ifdef _STD_MAIN
	ila     $3,0
#else
	ori     $3,$80,0
#endif
	brsl	$LR, __monstartup
#endif
	ori     $3,$80,0
	ori     $4,$81,0	
#ifndef _STD_MAIN
	ori	$5,$82,0
#endif

	/* Call the programs main.
	 */
	brsl	$LR, main
	
	/* Call exit.
	 */
	brsl	$LR, exit

