// crt1-sim.S // For the Xtensa simulator target, this code sets up the C calling context // and calls main() (via __clibrary_start). // Control arrives here at _start from the reset vector or from crt0-app.S. // Copyright (c) 1998-2010 Tensilica Inc. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include #include "xtos-internal.h" // Exports .global _start // Imports // __clibrary_init from C library (eg. newlib or uclibc) // exit from C library // main from user application // __stack from linker script (see LSP Ref Manual) .type __clibrary_init, @function .type main, @function .type exit, @function // Macros to abstract away ABI differences #if __XTENSA_CALL0_ABI__ # define CALL call0 # define ARG1 a2 /* 1st outgoing call argument */ # define ARG2 a3 /* 2nd outgoing call argument */ # define ARG3 a4 /* 3rd outgoing call argument */ # define ARG4 a5 /* 4th outgoing call argument */ # define ARG5 a6 /* 5th outgoing call argument */ #else # define CALL call4 # define ARG1 a6 /* 1st outgoing call argument */ # define ARG2 a7 /* 2nd outgoing call argument */ # define ARG3 a8 /* 3rd outgoing call argument */ # define ARG4 a9 /* 4th outgoing call argument */ # define ARG5 a10 /* 5th outgoing call argument */ #endif .data .weak _start_envp // allow overriding .align 4 _start_envp: .word 0 // empty environ .text .align 4 _start: // _start is typically NOT at the beginning of the text segment -- // it is always called from either the reset vector or other code // that does equivalent initialization (such as crt0-app.S). // // Assumptions on entry to _start: // - low (level-one) and medium priority interrupts are disabled // via PS.INTLEVEL and/or INTENABLE (PS.INTLEVEL is expected to // be zeroed, to potentially enable them, before calling main) // - C calling context not initialized: // - PS not initialized // - SP not initialized // - the following are initialized: // - LITBASE, cache attributes, WindowBase, WindowStart, // CPENABLE, FP's FCR and FSR, EXCSAVE[n] // Keep a0 zero. It is used to initialize a few things. // It is also the return address, where zero indicates // that the frame used by _start is the bottommost frame. // movi a0, 0 // keep this register zero. #if XTOS_RESET_UNNEEDED #include "reset-unneeded.S" #endif // Initialize the stack pointer. // See the "ABI and Software Conventions" chapter in the // Xtensa ISA Reference manual for details. // NOTE: Because the _start routine does not use any memory in its // stack frame, and because all of its CALL instructions use a // window size of 4, the stack frame for _start can be empty. movi sp, __stack // reserve stack space for // - argv array // - argument strings movi a2, SYS_iss_argv_size simcall // returns size of argv[] + its strings in a2 #if XCHAL_HAVE_PIF // The stack only needs 16-byte alignment. // However, here we round up the argv size further to 128 byte multiples // so that in most cases, variations in argv[0]'s path do not result in // different stack allocation. Otherwise, such variations can impact // execution timing (eg. due to cache effects etc) for the same code and data. // If we have a PIF, it's more likely the extra required space is okay. addi a2, a2, 127 srli a2, a2, 7 slli a2, a2, 7 #else // Keep stack 16-byte aligned. addi a2, a2, 15 srli a2, a2, 4 slli a2, a2, 4 #endif // No need to use MOVSP because we have no caller (we're the // base caller); in fact it's better not to use MOVSP in this // context, to avoid unnecessary ALLOCA exceptions and copying // from undefined memory: // sub a3, sp, a2 // movsp sp, a3 sub sp, sp, a2 /* * Now that sp (a1) is set, we can set PS as per the application * (user vector mode, enable interrupts, enable window exceptions if applicable). */ #if XCHAL_HAVE_EXCEPTIONS # ifdef __XTENSA_CALL0_ABI__ movi a3, PS_UM // PS.WOE = 0, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0 # else movi a3, PS_UM|PS_WOE // PS.WOE = 1, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0 # endif wsr a3, PS rsync #endif /* The new ISS simcall only appeared after RB-2007.2: */ #if !XCHAL_HAVE_BOOTLOADER && (XCHAL_HW_MAX_VERSION > XTENSA_HWVERSION_RB_2007_2) /* pre-LX2 cores only */ /* * Clear the BSS (uninitialized data) segments. * This code supports multiple zeroed sections (*.bss). * For speed, we clear memory using an ISS simcall * (see crt1-boards.S for more generic BSS clearing code). */ movi a6, _bss_table_start movi a7, _bss_table_end bgeu a6, a7, .Lnobss .Lbssloop: movi a2, SYS_memset l32i a3, a6, 0 // arg1 = fill start address movi a4, 0 // arg2 = fill pattern l32i a5, a6, 4 // get end address addi a6, a6, 8 // next bss table entry sub a5, a5, a3 // arg3 = fill size in bytes simcall // memset(a3,a4,a5) bltu a6, a7, .Lbssloop // loop until end of bss table .Lnobss: #endif /* * Call __clibrary_init to initialize the C library: * * void __clibrary_init(int argc, char ** argv, char ** environ, * void(*init_func)(void), void(*fini_func)(void)); */ // Get argv with the arguments from the ISS mov a3, sp // tell simcall where to write argv[] movi a2, SYS_iss_set_argv simcall // write argv[] array at a3 movi a2, SYS_iss_argc simcall // put argc in a2 // Alternative smaller code for Xtensa TX. // Many starting with simulation assume a full C env, so NOT DONE FOR NOW. // //#if XCHAL_HAVE_HALT // // // Assume minimalist environment for memory-constrained TX cores. // // No C library or board initialization, and no call to exit(). // // However, in the interest of software regressions, for now we // // still pass parameters to main (but not the rarely used envp). // // //mov ARG1, a2 // argc already in a2. // mov ARG2, sp // argv // CALL main // halt // //#else /* !HALT */ // ... #if __XTENSA_CALL0_ABI__ mov a12, a2 // save argc (a2 is ARG1) #else mov ARG1, a2 // argc #endif mov ARG2, sp // argv movi ARG3, _start_envp // envp movi ARG4, _init // _init movi ARG5, _fini // _fini CALL __clibrary_init // Call: int main(int argc, char ** argv, char ** environ); #if __XTENSA_CALL0_ABI__ mov ARG1, a12 // argc #else mov ARG1, a2 // argc #endif mov ARG2, sp // argv movi ARG3, _start_envp // envp = [0] CALL main // The return value is the same register as the first outgoing argument. CALL exit // exit with main's return value // Does not return here. .size _start, . - _start // Local Variables: // mode:fundamental // comment-start: "// " // comment-start-skip: "// *" // End: