.section ".crt0", "ax"
.arm

.global _start
.type _start, %function
_start:
    // disable irqs
    ldr r0,= 0x04000208
    strb r0, [r0]
    // configure cp15
    // disable itcm, dtcm, caches and mpu
    ldr r0,= 0x00002078
    mcr p15, 0, r0, c1, c0
    mov r0, #0
    // invalidate entire icache
    mcr p15, 0, r0, c7, c5, 0
    // invalidate entire dcache
    mcr p15, 0, r0, c7, c6, 0
    // drain write buffer
    mcr p15, 0, r0, c7, c10, 4
    // move dtcm in place
    ldr r0,= __dtcm_start + 0xA
    mcr p15, 0, r0, c9, c1, 0
    // setup itcm to cover the first 32MB of memory
    mov r0, #0x20
    mcr p15, 0, r0, c9, c1, 1
    // mpu region 0: IO, Palette, VRAM, OAM (64 MB)
    ldr r0,= ((1 | (25 << 1)) + 0x04000000)
    mcr	p15, 0, r0, c6, c0, 0
    // mpu region 1: Main Memory + TWL WRAM (32 MB)
    ldr r0,= ((1 | (24 << 1)) + 0x02000000)
    mcr	p15, 0, r0, c6, c1, 0
    // mpu region 2: GBA slot
    ldr r0,= ((1 | (24 << 1)) + 0x08000000)
    mcr	p15, 0, r0, c6, c2, 0
    // mpu region 3: Disabled
    mov r0, #0
    mcr	p15, 0, r0, c6, c3, 0
    // mpu region 4: Disabled
    mov r0, #0
    mcr	p15, 0, r0, c6, c4, 0
    // mpu region 5: ITCM (32 KB)
    ldr r0,= ((1 | (14 << 1)) + __itcm_start)
    mcr	p15, 0, r0, c6, c5, 0
    // mpu region 6: DTCM (16 KB)
    ldr r0,= ((1 | (13 << 1)) + __dtcm_start)
    mcr	p15, 0, r0, c6, c6, 0
    // mpu region 7: LCDC VRAM A (128 KB)
    ldr r0,= (1 | (16 << 1) | 0x06800000)
    mcr	p15, 0, r0, c6, c7, 0
    // data permissions
    ldr r0,= 0x33300333
    mcr p15, 0, r0, c5, c0, 2
    // code permissions
    ldr r0,= 0x30300330
    mcr p15, 0, r0, c5, c0, 3
    // dcache
    ldr r0,= 0b10000010
    mcr p15, 0, r0, c2, c0, 0
    // icache
    ldr r0,= 0b10000010
    mcr p15, 0, r0, c2, c0, 1
    // write buffer
    ldr r0,= 0b10000010
    mcr p15, 0, r0, c3, c0, 0

    // turn back on itcm, dtcm, cache and mpu
    // keep data cache off
    ldr r0,= 0x00057079 //0x0005707D
    mcr p15, 0, r0, c1, c0

    // copy itcm in place
    ldr r0,= __itcm_lma
    ldr r2,= __itcm_start
    ldr r1,= __itcm_end
    subs r1, r1, r2
    beq itcm_done
1:
    ldmia r0!, {r3-r10}
    stmia r2!, {r3-r10}
    subs r1, #0x20
    bgt 1b
itcm_done:

    // copy dtcm in place
    ldr r0,= __dtcm_lma
    ldr r2,= __dtcm_start
    ldr r1,= __dtcm_end
    subs r1, r1, r2
    beq dtcm_done
1:
    ldmia r0!, {r3-r10}
    stmia r2!, {r3-r10}
    subs r1, #0x20
    bgt 1b
dtcm_done:

    // clear bss
    ldr r0,= __bss_start
    ldr r1,= __bss_end
    cmp r0, r1
    beq bss_done
    mov r2, #0
1:
    str r2, [r0], #4
    cmp r0, r1
    bne 1b
bss_done:
    msr cpsr_c, #0x13 // svc
    ldr sp,= __dtcm_start + 0x3FC0
    msr cpsr_c, #0x12 // irq
    ldr sp,= __dtcm_start + 0x3F80
    msr cpsr_c, #0x1F // sys
    ldr sp,= __dtcm_start + 0x2F7C
    b loaderMain

.pool
.end
