blob: a66fe84e6be8f77f1daf1262ad55e16778792b2f [file] [log] [blame]
// crt1-boards.S
//
// For most hardware / boards, this code sets up the C calling context
// (setting up stack, PS, and clearing BSS) and jumps to __clibrary_start
// which sets up the C library, calls constructors and registers destructors,
// and calls main().
//
// 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 <xtensa/coreasm.h>
#include <config.h>
// DF #include "xtos-internal.h"
//#include <xtensa/../../src/xtos/xtos-internal.h>
//.global _ResetVector
#if 0
/*
* Reset vector.
* Only a trampoline to jump to _start
* (Note that we have to mark the section writable as the section contains
* a relocatable literal)
*/
.section .ResetVector.text, "awx"
.global _ResetVector
_ResetVector:
j 1f
.align 4
2: .long _start
1: l32r a2, 2b
jx a2
#endif
// Exports
.global _start
// Imports
// __clibrary_init from C library (eg. newlib or uclibc)
// exit from C library
// main from user application
// board_init board-specific (uart/mingloss/tinygloss.c)
// xthal_dcache_all_writeback from HAL library
// __stack from linker script (see LSP Ref Manual)
// _bss_table_start from linker script (see LSP Ref Manual)
// _bss_table_end from linker script (see LSP Ref Manual)
.type main, @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 CALLX callx4
# 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
/**************************************************************************/
.text
.align 4
.literal_position
_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.
//
// not needed for Xtensa TX
#if !XCHAL_HAVE_HALT || !defined(CONFIG_BOOT_LOADER)
movi a0, 0 // keep this register zero.
#endif
#if XTOS_RESET_UNNEEDED && !XCHAL_HAVE_HALT
#include "reset-unneeded.S"
#endif
#if defined(CONFIG_BOOT_LOADER)
.weak _Level2FromVector
.weak _Level3FromVector
.weak _Level4FromVector
.weak _Level5FromVector
movi a4, _Level2FromVector
wsr a4, EXCSAVE+2
movi a4, _Level3FromVector
wsr a4, EXCSAVE+3
movi a4, _Level4FromVector
wsr a4, EXCSAVE+4
movi a4, _Level5FromVector
wsr a4, EXCSAVE+5
#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 (or zero), the stack frame for _start can be empty.
movi sp, __stack
/*
* 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__
// PS.WOE = 0, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0
movi a3, PS_UM
# else
// PS.WOE = 1, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0
movi a3, PS_UM|PS_WOE
# endif
wsr a3, PS
rsync
#endif
/*
* Do any initialization that affects the memory map, such as
* setting up TLB entries, that needs to be done before we can
* successfully clear BSS (e.g. if some BSS segments are in
* remapped areas).
*
* NOTE: This hook works where the reset vector does not unpack
* segments (see "ROM packing" in the LSP manual), or where
* unpacking of segments is not affected by memory remapping.
* If ROM unpacking is affected, TLB setup must be done in
* assembler from the reset vector.
*
* The __memmap_init() routine can be a C function, however it
* does not have BSS initialized! In particular, __memmap_init()
* cannot set BSS variables, i.e. uninitialized global variables
* (they'll be wiped out by the following BSS clear), nor can it
* assume they are yet initialized to zero.
*
* The __memmap_init() function is optional. It is marked as a
* weak symbol, so that it gets valued zero if not defined.
*/
.weak __memmap_init
movi a4, __memmap_init
beqz a4, 1f
CALLX a4
1:
/* boot loader takes care of zeroing BSS */
#if !defined(CONFIG_BOOT_LOADER)
/*
* Clear the BSS (uninitialized data) segments.
* This code supports multiple zeroed sections (*.bss).
*
* Register allocation:
* a0 = 0
* a6 = pointer to start of table, and through table
* a7 = pointer to end of table
* a8 = start address of bytes to be zeroed
* a9 = end address of bytes to be zeroed
* a10 = length of bytes to be zeroed
*/
movi a0, 0
movi a6, _bss_table_start
movi a7, _bss_table_end
bgeu a6, a7, .L3zte
.L0zte: l32i a8, a6, 0 // get start address, assumed multiple of 4
l32i a9, a6, 4 // get end address, assumed multiple of 4
addi a6, a6, 8 // next entry
sub a10, a9, a8 // a10 = length, assumed a multiple of 4
bbci.l a10, 2, .L1zte
s32i a0, a8, 0 // clear 4 bytes to make length multiple of 8
addi a8, a8, 4
.L1zte: bbci.l a10, 3, .L2zte
s32i a0, a8, 0 // clear 8 bytes to make length multiple of 16
s32i a0, a8, 4
addi a8, a8, 8
.L2zte: srli a10, a10, 4 // length is now multiple of 16, divide by 16
floopnez a10, clearzte
s32i a0, a8, 0 // clear 16 bytes at a time...
s32i a0, a8, 4
s32i a0, a8, 8
s32i a0, a8, 12
addi a8, a8, 16
floopend a10, clearzte
bltu a6, a7, .L0zte // loop until end of table of *.bss sections
.L3zte:
#endif
// We can now call C code,
// the C calling environment has been initialized.
//
// From this point on, we use ABI-specific macros to refer
// to registers a0 .. a15
// (ARG#).
#if XCHAL_HAVE_HALT
// Assume minimalist environment for memory-constrained TX cores.
// No C library or board initialization, no parameters passed to main
// (assume declared as "void main(void)") and no call to exit().
CALL main
halt
#else /* !HALT */
.type board_init, @function
.type __clibrary_init, @function
.type exit, @function
// Initialize the board (eg. the UART on the XT2000).
//CALL board_init
/*
* 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));
*/
// Pass an empty argv array, with an empty string as the program name.
#if 0
movi ARG1, _start_argc // argc address
movi ARG2, _start_argv // argv = ["", 0]
movi ARG3, _start_envp // envp = [0]
// movi ARG4, _init // function that calls constructors
// movi ARG5, _fini // function that calls destructors
l32i ARG1, ARG1, 0 // argc = 1
CALL __clibrary_init
#endif
// Call: int main(int argc, char ** argv, char ** environ);
movi ARG1, _start_argc // argc address
movi ARG2, _start_argv // argv = ["", 0]
movi ARG3, _start_envp // envp = [0]
l32i ARG1, ARG1, 0 // argc = 1
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.
.data
// Mark argc/argv/envp parameters as weak so that an external
// object file can override them.
.weak _start_argc, _start_argv, _start_envp
.align 4
_start_argv:
.word _start_null // empty program name
_start_null:
_start_envp:
.word 0 // end of argv array, empty string, empty environ
_start_argc:
.word 1 // one argument (program name)
.text
#endif /* !HALT */
.size _start, . - _start
//#endif