# _____     ___ ____     ___ ____
#  ____|   |    ____|   |        | |____|
# |     ___|   |____ ___|    ____| |    \    PS2DEV Open Source Project.
#-----------------------------------------------------------------------
# Copyright (c) 2001-2007 ps2dev - http://www.ps2dev.org
# Licenced under Academic Free License version 2.0
# Review ps2sdk README & LICENSE files for further details.
#
# $Id: crt0.s 1514 2009-01-16 23:49:17Z radad $
# Standard startup file.

   .weak  _init
   .type  _init, @function

   .weak  _fini
   .type  _fini, @function

   .extern   _heap_size
   .extern   _stack
   .extern   _stack_size   

   .weakext _ps2sdk_args_parse_weak, _ps2sdk_args_parse
   .globl   _ps2sdk_args_parse_weak
   .type    _ps2sdk_args_parse_weak, @function

   .weakext _ps2sdk_libc_init_weak, _ps2sdk_libc_init
   .globl   _ps2sdk_libc_init_weak
   .type    _ps2sdk_libc_init_weak, @function

   .weakext _ps2sdk_libc_deinit_weak, _ps2sdk_libc_deinit
   .globl   _ps2sdk_libc_deinit_weak
   .type    _ps2sdk_libc_deinit_weak, @function

   .set   noat
   .set   noreorder

   .text
   .align   2

   nop
   nop

   .globl  _start
   .ent    _start
_start:

zerobss:
   # clear bss area

   la   $2, _fbss
   la   $3, _end

1:
   sltu   $1, $2, $3
   beq   $1, $0, 2f
   nop
   sq   $0, ($2)
   addiu   $2, $2, 16
   j   1b
   nop
2:

   # store eventual loader arguments (passed via a0)

   la   $2, _loader_args
   sw   $4, ($2)

setupthread:
   # setup current thread

   la   $4, _gp
   la   $5, _stack
   la   $6, _stack_size
   la   $7, _args
   la   $8, _root
   move   $gp, $4
   addiu   $3, $0, 60
   syscall         # SetupThread(_gp, _stack, _stack_size, _args, _root)
   move   $sp, $2

   # initialize heap

   la   $4, _end
   la   $5, _heap_size
   addiu   $3, $0, 61
   syscall         # SetupHeap(_end, _heap_size)

   # writeback data cache

   move   $4, $0
   addiu   $3, $0, 100
   syscall         # FlushCache(0)

parseargs:
   # call ps2sdk argument parsing (weak)

   la   $8, _ps2sdk_args_parse_weak
   beqz   $8, 1f
   nop

   jal   _getargs
   nop
   jalr   $8      # _ps2sdk_args_parse(argc, argv)
   nop
1:

libc_init:
   # initialize ps2sdk libc (weak)

   la   $8, _ps2sdk_libc_init_weak
   beqz   $8, 1f
   nop
   jalr   $8      # _ps2sdk_libc_init()
   nop
1:   

ctors:
   # call global constructors (weak)

   la   $8, _init
   beqz   $8, 1f
   nop
   jalr   $8      # _init()
   nop
1:

   # call main

   ei
   jal   _getargs
   nop
   jal   main      # main(argc, argv)
   nop

   # call _exit

   j   _exit      # _exit(retval)
   move   $4, $2
   .end   _start

   .align   3

   .globl   _exit
   .ent   _exit
   .text
_exit:
   la   $2, _retval
   sw   $4, ($2)

dtors:
   # call global destructors (weak)

   la   $8, _fini
   beqz   $8, 1f
   nop
   jalr   $8      # _fini()
   nop
1:

libc_uninit:
   # uninitialize ps2sdk libc (weak)

   la   $8, _ps2sdk_libc_deinit_weak
   beqz   $8, 1f
   nop
   jalr   $8      # _ps2sdk_libc_deinit()
   nop
1:

   # conditional exit (depending on if we got arguments through the loader or not)

   la   $2, _retval
   lw   $4, ($2)

   la   $5, _loader_args
   lw   $6, ($5)
   beqz   $6, 1f
   nop

   # called from a loader, close thread

   lw   $7, ($6)
   sw   $0, ($7)   # clear thread id

   addiu   $3, $0, 36
   syscall         # ExitDeleteThread() (noreturn)
1:

   # not called from a loader, return to browser

   addiu   $3, $0, 4
   syscall         # Exit(retval) (noreturn)

   .end   _exit

   .ent   _root
_root:
   addiu   $3, $0, 35
   syscall         # ExitThread() (noreturn)
   .end   _root

   .ent   _getargs
_getargs:
   # check normal arguments

   la   $2, _args
   lw   $3, ($2)
   bnez   $3, 1f
   nop

   # check for arguments passed by a loader

   la   $2, _loader_args
   lw   $3, ($2)
   beqzl   $3, 2f
   addu   $4, $0, 0

   addiu   $2, $3, 4
1:
   lw   $4, ($2)
   addiu   $5, $2, 4
2:
   jr   $ra      # $4 = argc, $5 = argv
   nop
   .end   _getargs

   .bss
   .align   6
_args:
   .space   4+16*4+256   # argc, 16 arguments, 256 bytes payload
_loader_args:
   .space   4      # pointer to loader arguments: thread id, argc, argv
_retval:
   .space   4
