// this file was taken from libogc, see http://www.devkitpro.org/

#include "asm.h"

#define _SDA_BASE_ 32768
#define _SDA2_BASE_ 32768


        .text
        .section .init

        # crt0.s file for the GameCube V1.1 by Costis (costis@gbaemu.com)!
        #
        # Updates: Added support for clearing the BSS section so that global
        #            variables are cleared to 0 upon start-up. 
        #
        # This is start-up code for initializing the GameCube system and hardware
        # before executing the actual user program code. It clears the GPR's,
        # initializes the FPR's, initializes the Data, Code, and L2 caches, clears
        # and initializes SPR's, and disables exceptions (interrupts).
        #
        # Have fun!!! Please e-mail any suggestions or bugs to costis@gbaemu.com.

        # Entry Point

        .extern __PSInit
        .extern __SyscallInit
        .extern __CacheInit
        .extern __SystemInit
        .extern __sbss_start, __bss_end
        .extern __bat_config
        .extern _main
        .globl _start, __main
_start:
        b startup
        .ascii "STUB"
        .ascii "HAXX"
        .long 0
startup:
        # Disable interrupts first thing
        mfmsr   r3
        rlwinm  r4,r3,0,17,15
        rlwinm  r4,r4,0,26,24
        mtmsr   r4

        # Go into real mode
        isync
        lis     r3,real@h
        ori     r3,r3,real@l
        clrlwi  r3,r3,2
        mtsrr0  r3

        mfmsr   r3
        li      r4,0x30
        andc    r3,r3,r4
        mtsrr1  r3
        rfi
        
real:
        # Set up the BATs the way we like them
        // HID0 = 00110c64:
        // bus checkstops off, sleep modes off,
        // caches off, caches invalidate,
        // store gathering off, enable data cache
        // flush assist, enable branch target cache,
        // enable branch history table
        lis 3,0x0011 ; ori 3,3,0x0c64 ; mtspr 1008,3 ; isync

        // MSR = 00002000 (FP on)
        li 4,0x2000 ; mtmsr 4

        // HID0 |= 0000c000 (caches on)
        ori 3,3,0xc000 ; mtspr 1008,3 ; isync

        // clear all BATs
        li 0,0
        mtspr 528,0 ; mtspr 530,0 ; mtspr 532,0 ; mtspr 534,0 // IBATU 0..3
        mtspr 536,0 ; mtspr 538,0 ; mtspr 540,0 ; mtspr 542,0 // DBATU 0..3
        mtspr 560,0 ; mtspr 562,0 ; mtspr 564,0 ; mtspr 566,0 // IBATU 4..7
        mtspr 568,0 ; mtspr 570,0 ; mtspr 572,0 ; mtspr 574,0 // DBATU 4..7
        isync

        // clear all SRs
        lis 0,0x8000
        mtsr  0,0 ; mtsr  1,0 ; mtsr  2,0 ; mtsr  3,0
        mtsr  4,0 ; mtsr  5,0 ; mtsr  6,0 ; mtsr  7,0
        mtsr  8,0 ; mtsr  9,0 ; mtsr 10,0 ; mtsr 11,0
        mtsr 12,0 ; mtsr 13,0 ; mtsr 14,0 ; mtsr 15,0
        isync

        // set [DI]BAT0 for 256MB@80000000,
        // real 00000000, WIMG=0000, R/W
        li 3,2 ; lis 4,0x8000 ; ori 4,4,0x1fff
        mtspr IBAT0L,3 ; mtspr IBAT0U,4 ; mtspr DBAT0L,3 ; mtspr DBAT0U,4 ; isync

        // set [DI]BAT4 for 256MB@90000000,
        // real 10000000, WIMG=0000, R/W
        addis 3,3,0x1000 ; addis 4,4,0x1000
        mtspr IBAT4L,3 ; mtspr IBAT4U,4 ; mtspr DBAT4L,3 ; mtspr DBAT4U,4 ; isync

        // set DBAT1 for 256MB@c0000000,
        // real 00000000, WIMG=0101, R/W
        li 3,0x2a ; lis 4,0xc000 ; ori 4,4,0x1fff
        mtspr DBAT1L,3 ; mtspr DBAT1U,4 ; isync

        // set DBAT5 for 256MB@d0000000,
        // real 10000000, WIMG=0101, R/W
        addis 3,3,0x1000 ; addis 4,4,0x1000
        mtspr DBAT5L,3 ; mtspr DBAT5U,4 ; isync

        // enable [DI]BAT4-7 in HID4
        lis 3, 0x8200
        mtspr 1011,3

        // set MSR[DR:IR] = 11, jump to _start
        lis 3,virtual@h ; ori 3,3, virtual@l ; mtsrr0 3

        mfmsr 3 ; ori 3,3,0x30 ; mtsrr1 3
        rfi

virtual:

        bl      InitGPRS                # Initialize the General Purpose Registers
        bl      __CacheInit             # Initialize the system caches
        bl      __SyscallInit           # Initialize the System Call handler
        bl      __SystemInit            # Initialize more cache aspects, clear a few SPR's, and disable interrupts.

        # Clear the BSS section!
        lis             r3,__sbss_start@h
        ori             r3,r3,__sbss_start@l
        li              r4,0
        lis             r5,__bss_end@h
        ori             r5,r5,__bss_end@l
        sub             r5,r5,r3
        bl              _memset

        bl      _main # Branch to the user code!

eloop:
        b eloop                 # If the main function returns, which should never happen then just loop endlessly.

InitGPRS:
        # Clear all of the GPR's to 0
        li      r0,0
        li      r3,0
        li      r4,0
        li      r5,0
        li      r6,0
        li      r7,0
        li      r8,0
        li      r9,0
        li      r10,0
        li      r11,0
        li      r12,0
        li      r14,0
        li      r15,0
        li      r16,0
        li      r17,0
        li      r18,0
        li      r19,0
        li      r20,0
        li      r21,0
        li      r22,0
        li      r23,0
        li      r24,0
        li      r25,0
        li      r26,0
        li      r27,0
        li      r28,0
        li      r29,0
        li      r30,0
        li      r31,0

        lis             sp,__crt0stack@h                    # we take 0x8173FFF0 as the topmost starting point for our stack,this gives us ~128Kb Stack
        ori             sp,sp,__crt0stack@l
        addi    sp,sp,-4
        stw             r0,0(sp)
        stwu    sp,-56(sp)

        lis     r2,_SDA2_BASE_@h
        ori     r2,r2,_SDA2_BASE_@l  # Set the Small Data 2 (Read Only) base register.
        lis     r13,_SDA_BASE_@h
        ori     r13,r13,_SDA_BASE_@l # Set the Small Data (Read\Write) base register.   
        blr

        //r3 = ptr, r4 = fill, r5 = size
        .globl _memset
_memset:
        clrlwi. r6,r5,29
        srwi    r5,r5,2
        subi    r3,r3,4
        mtctr   r5
1:      stwu    r4,4(r3)
        bdnz    1b
        cmplwi  r6,0
        beq             3f
2:      stbu    r4,1(r3)
        addic.  r6,r6,-1
        bne+    2b
3:      blr

        .section .bss
        .balign 8
__crt0stack_end:
        .space 0x8000
__crt0stack: