diff --git a/CMakeLists.txt b/CMakeLists.txt index 91407876..ffb83a65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,10 @@ endif() enable_testing() +if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA") + add_subdirectory(deps/gbastartup) +endif() + add_subdirectory(deps/ox) include_directories(deps/ox/src) diff --git a/deps/gbastartup/CMakeLists.txt b/deps/gbastartup/CMakeLists.txt new file mode 100644 index 00000000..203bbb72 --- /dev/null +++ b/deps/gbastartup/CMakeLists.txt @@ -0,0 +1,10 @@ +enable_language(C ASM) +add_library( + GbaStartup + gba_crt0.s + cstartup.cpp +) + +target_link_libraries( + GbaStartup +) diff --git a/deps/gbastartup/cstartup.c b/deps/gbastartup/cstartup.c new file mode 100644 index 00000000..3c4ea5ce --- /dev/null +++ b/deps/gbastartup/cstartup.c @@ -0,0 +1,9 @@ + +extern void (*__preinit_array_start[]) (void); +extern void (*__preinit_array_end[]) (void); +extern void (*__init_array_start[]) (void); +extern void (*__init_array_end[]) (void); + +extern "C" void __libc_init_array() { + auto count = __preinit_array_end - __preinit_array_start; +} diff --git a/deps/gbastartup/cstartup.cpp b/deps/gbastartup/cstartup.cpp new file mode 100644 index 00000000..481e9105 --- /dev/null +++ b/deps/gbastartup/cstartup.cpp @@ -0,0 +1,16 @@ + +extern void (*__preinit_array_start[]) (void); +extern void (*__preinit_array_end[]) (void); +extern void (*__init_array_start[]) (void); +extern void (*__init_array_end[]) (void); + +extern "C" void __libc_init_array() { + auto preInits = __preinit_array_end - __preinit_array_start; + for (decltype(preInits) i = 0; i < preInits; i++) { + __preinit_array_start[i](); + } + auto inits = __init_array_end - __init_array_start; + for (decltype(inits) i = 0; i < inits; i++) { + __preinit_array_start[i](); + } +} diff --git a/deps/gbastartup/gba_crt0.s b/deps/gbastartup/gba_crt0.s new file mode 100644 index 00000000..a0816b5d --- /dev/null +++ b/deps/gbastartup/gba_crt0.s @@ -0,0 +1,260 @@ +/*-------------------------------------------------------------------------------- + Copyright devkitPro Project + https://github.com/devkitPro/devkitarm-crtls/blob/master/gba_crt0.s + + This Source Code Form is subject to the terms of the Mozilla Public License, + v. 2.0. If a copy of the MPL was not distributed with this file, You can + obtain one at https://mozilla.org/MPL/2.0/. +--------------------------------------------------------------------------------*/ + + .section ".crt0","ax" + .global _start + .align + + .arm + .cpu arm7tdmi + +@--------------------------------------------------------------------------------- +_start: +@--------------------------------------------------------------------------------- + b rom_header_end + + .fill 156,1,0 @ Nintendo Logo Character Data (8000004h) + .fill 16,1,0 @ Game Title + .byte 0x30,0x31 @ Maker Code (80000B0h) + .byte 0x96 @ Fixed Value (80000B2h) + .byte 0x00 @ Main Unit Code (80000B3h) + .byte 0x00 @ Device Type (80000B4h) + .fill 7,1,0 @ unused + .byte 0x00 @ Software Version No (80000BCh) + .byte 0xf0 @ Complement Check (80000BDh) + .byte 0x00,0x00 @ Checksum (80000BEh) + +@--------------------------------------------------------------------------------- +rom_header_end: +@--------------------------------------------------------------------------------- + b start_vector @ This branch must be here for proper + @ positioning of the following header. + + .GLOBAL __boot_method, __slave_number +@--------------------------------------------------------------------------------- +__boot_method: +@--------------------------------------------------------------------------------- + .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot) +@--------------------------------------------------------------------------------- +__slave_number: +@--------------------------------------------------------------------------------- + .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3) + + .byte 0 @ reserved + .byte 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + + .global start_vector + .align +@--------------------------------------------------------------------------------- +start_vector: +@--------------------------------------------------------------------------------- + mov r0, #0x4000000 @ REG_BASE + str r0, [r0, #0x208] + + mov r0, #0x12 @ Switch to IRQ Mode + msr cpsr, r0 + ldr sp, =__sp_irq @ Set IRQ stack + mov r0, #0x1f @ Switch to System Mode + msr cpsr, r0 + ldr sp, =__sp_usr @ Set user stack + +@--------------------------------------------------------------------------------- +@ Enter Thumb mode +@--------------------------------------------------------------------------------- + add r0, pc, #1 + bx r0 + + .thumb + + ldr r0, =__text_start + lsl r0, #5 @ Was code compiled at 0x08000000 or higher? + bcs DoEWRAMClear @ yes, you can not run it in external WRAM + + mov r0, pc + lsl r0, #5 @ Are we running from ROM (0x8000000 or higher) ? + bcc SkipEWRAMClear @ No, so no need to do a copy. + +@--------------------------------------------------------------------------------- +@ We were started in ROM, silly emulators. :P +@ So we need to copy to ExWRAM. +@--------------------------------------------------------------------------------- + mov r2, #2 + lsl r2, r2, #24 @ r2= 0x02000000 + ldr r3, =__end__ @ last ewram address + sub r3, r2 @ r3= actual binary size + mov r6, r2 @ r6= 0x02000000 + lsl r1, r2, #2 @ r1= 0x08000000 + + bl CopyMem + + bx r6 @ Jump to the code to execute + +@--------------------------------------------------------------------------------- +DoEWRAMClear: @ Clear External WRAM to 0x00 +@--------------------------------------------------------------------------------- + mov r1, #0x40 + lsl r1, #12 @ r1 = 0x40000 + lsl r0, r1, #7 @ r0 = 0x2000000 + bl ClearMem + +@--------------------------------------------------------------------------------- +SkipEWRAMClear: @ Clear Internal WRAM to 0x00 +@--------------------------------------------------------------------------------- + +@--------------------------------------------------------------------------------- +@ Clear BSS section to 0x00 +@--------------------------------------------------------------------------------- + ldr r0, =__bss_start__ + ldr r1, =__bss_end__ + sub r1, r0 + bl ClearMem + +@--------------------------------------------------------------------------------- +@ Clear SBSS section to 0x00 +@--------------------------------------------------------------------------------- + ldr r0, =__sbss_start__ + ldr r1, =__sbss_end__ + sub r1, r0 + bl ClearMem + +@--------------------------------------------------------------------------------- +@ Copy initialized data (data section) from LMA to VMA (ROM to RAM) +@--------------------------------------------------------------------------------- + ldr r1, =__data_lma + ldr r2, =__data_start__ + ldr r4, =__data_end__ + bl CopyMemChk + +@--------------------------------------------------------------------------------- +@ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM) +@--------------------------------------------------------------------------------- + ldr r1,= __iwram_lma + ldr r2,= __iwram_start__ + ldr r4,= __iwram_end__ + bl CopyMemChk + +@--------------------------------------------------------------------------------- +@ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM) +@--------------------------------------------------------------------------------- + ldr r2,= __load_stop_iwram0 + ldr r1,= __load_start_iwram0 + sub r3, r2, r1 @ Is there any data to copy? + beq CIW0Skip @ no + + ldr r2,= __iwram_overlay_start + bl CopyMem +@--------------------------------------------------------------------------------- +CIW0Skip: +@--------------------------------------------------------------------------------- +@ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM) +@--------------------------------------------------------------------------------- + ldr r1, =__ewram_lma + ldr r2, =__ewram_start + ldr r4, =__ewram_end + bl CopyMemChk + +@--------------------------------------------------------------------------------- +CEW0Skip: +@--------------------------------------------------------------------------------- +@ set heap end +@--------------------------------------------------------------------------------- + // fake_heap_end does not appear to exist, + // and Nostalgia has its own heap allocator anyway + //ldr r1, =fake_heap_end + //ldr r0, =__eheap_end + //str r0, [r1] +@--------------------------------------------------------------------------------- +@ global constructors +@--------------------------------------------------------------------------------- + ldr r3, =__libc_init_array + bl _blx_r3_stub +@--------------------------------------------------------------------------------- +@ Jump to user code +@--------------------------------------------------------------------------------- + mov r0, #0 @ int argc + mov r1, #0 @ char *argv[] + ldr r3, =main + bl _blx_r3_stub +@--------------------------------------------------------------------------------- +@ Clear memory to 0x00 if length != 0 +@--------------------------------------------------------------------------------- +@ r0 = Start Address +@ r1 = Length +@--------------------------------------------------------------------------------- +ClearMem: +@--------------------------------------------------------------------------------- + mov r2,#3 @ These commands are used in cases where + add r1,r2 @ the length is not a multiple of 4, + bic r1,r2 @ even though it should be. + + beq ClearMX @ Length is zero so exit + + mov r2,#0 +@--------------------------------------------------------------------------------- +ClrLoop: +@--------------------------------------------------------------------------------- + stmia r0!, {r2} + sub r1,#4 + bne ClrLoop +@--------------------------------------------------------------------------------- +ClearMX: +@--------------------------------------------------------------------------------- + bx lr + +@--------------------------------------------------------------------------------- +_blx_r3_stub: +@--------------------------------------------------------------------------------- + bx r3 + +@--------------------------------------------------------------------------------- +@ Copy memory if length != 0 +@--------------------------------------------------------------------------------- +@ r1 = Source Address +@ r2 = Dest Address +@ r4 = Dest Address + Length +@--------------------------------------------------------------------------------- +CopyMemChk: +@--------------------------------------------------------------------------------- + sub r3, r4, r2 @ Is there any data to copy? +@--------------------------------------------------------------------------------- +@ Copy memory +@--------------------------------------------------------------------------------- +@ r1 = Source Address +@ r2 = Dest Address +@ r3 = Length +@--------------------------------------------------------------------------------- +CopyMem: +@--------------------------------------------------------------------------------- + mov r0, #3 @ These commands are used in cases where + add r3, r0 @ the length is not a multiple of 4, + bic r3, r0 @ even though it should be. + beq CIDExit @ Length is zero so exit + +@--------------------------------------------------------------------------------- +CIDLoop: +@--------------------------------------------------------------------------------- + ldmia r1!, {r0} + stmia r2!, {r0} + sub r3, #4 + bne CIDLoop +@--------------------------------------------------------------------------------- +CIDExit: +@--------------------------------------------------------------------------------- + bx lr + + .align + .pool + .end +