/* | |
* CF_Startup.c - Default init/startup/termination routines for | |
* Embedded Metrowerks C++ | |
* | |
* Copyright © 1993-1998 Metrowerks, Inc. All Rights Reserved. | |
* Copyright © 2005 Freescale semiConductor Inc. All Rights Reserved. | |
* | |
* | |
* THEORY OF OPERATION | |
* | |
* This version of thestartup code is intended for linker relocated | |
* executables. The startup code will assign the stack pointer to | |
* __SP_INIT, assign the address of the data relative base address | |
* to a5, initialize the .bss/.sbss sections to zero, call any | |
* static C++ initializers and then call main. Upon returning from | |
* main it will call C++ destructors and call exit to terminate. | |
*/ | |
#ifdef __cplusplus | |
#pragma cplusplus off | |
#endif | |
#pragma PID off | |
#pragma PIC off | |
#include "startcf.h" | |
#include "RuntimeConfig.h" | |
/* imported data */ | |
extern unsigned long far _SP_INIT, _SDA_BASE; | |
extern unsigned long far _START_BSS, _END_BSS; | |
extern unsigned long far _START_SBSS, _END_SBSS; | |
extern unsigned long far __DATA_RAM, __DATA_ROM, __DATA_END; | |
/* imported routines */ | |
extern void __call_static_initializers(void); | |
extern int main(int, char **); | |
extern void exit(int); | |
/* exported routines */ | |
extern void _ExitProcess(void); | |
extern asm void _startup(void); | |
extern void __initialize_hardware(void); | |
extern void __initialize_system(void); | |
/* | |
* Dummy routine for initializing hardware. For user's custom systems, you | |
* can create your own routine of the same name that will perform HW | |
* initialization. The linker will do the right thing to ignore this | |
* definition and use the version in your file. | |
*/ | |
#pragma overload void __initialize_hardware(void); | |
void __initialize_hardware(void) | |
{ | |
} | |
/* | |
* Dummy routine for initializing systems. For user's custom systems, | |
* you can create your own routine of the same name that will perform | |
* initialization. The linker will do the right thing to ignore this | |
* definition and use the version in your file. | |
*/ | |
#pragma overload void __initialize_system(void); | |
void __initialize_system(void) | |
{ | |
} | |
/* | |
* Dummy routine for initializing C++. This routine will get overloaded by the C++ runtime. | |
*/ | |
#pragma overload void __call_static_initializers(void); | |
void __call_static_initializers(void) | |
{ | |
} | |
/* | |
* Routine to copy a single section from ROM to RAM ... | |
*/ | |
static __declspec(register_abi) void __copy_rom_section(char* dst, const char* src, unsigned long size) | |
{ | |
if (dst != src) | |
while (size--) | |
*dst++ = *src++; | |
} | |
/* | |
* Routine that copies all sections the user marked as ROM into | |
* their target RAM addresses ... | |
* | |
* __S_romp is automatically generated by the linker if it | |
* is referenced by the program. It is a table of RomInfo | |
* structures. The final entry in the table has all-zero | |
* fields. | |
*/ | |
static void __copy_rom_sections_to_ram(void) | |
{ | |
RomInfo *info; | |
/* | |
* Go through the entire table, copying sections from ROM to RAM. | |
*/ | |
for (info = _S_romp; info->Source != 0L || info->Target != 0L || info->Size != 0; ++info) | |
__copy_rom_section( (char *)info->Target,(char *)info->Source, info->Size); | |
} | |
/* | |
* Exit handler called from the exit routine, if your OS needs | |
* to do something special for exit handling just replace this | |
* routines with what the OS needs to do ... | |
*/ | |
asm void _ExitProcess(void) | |
{ | |
illegal | |
rts | |
} | |
/* | |
* Routine to clear out blocks of memory should give good | |
* performance regardless of 68k or ColdFire part. | |
*/ | |
static __declspec(register_abi) void clear_mem(char *dst, unsigned long n) | |
{ | |
unsigned long i; | |
long *lptr; | |
if (n >= 32) | |
{ | |
/* align start address to a 4 byte boundary */ | |
i = (- (unsigned long) dst) & 3; | |
if (i) | |
{ | |
n -= i; | |
do | |
*dst++ = 0; | |
while (--i); | |
} | |
/* use an unrolled loop to zero out 32byte blocks */ | |
i = n >> 5; | |
if (i) | |
{ | |
lptr = (long *)dst; | |
dst += i * 32; | |
do | |
{ | |
*lptr++ = 0; | |
*lptr++ = 0; | |
*lptr++ = 0; | |
*lptr++ = 0; | |
*lptr++ = 0; | |
*lptr++ = 0; | |
*lptr++ = 0; | |
*lptr++ = 0; | |
} | |
while (--i); | |
} | |
i = (n & 31) >> 2; | |
/* handle any 4 byte blocks left */ | |
if (i) | |
{ | |
lptr = (long *)dst; | |
dst += i * 4; | |
do | |
*lptr++ = 0; | |
while (--i); | |
} | |
n &= 3; | |
} | |
/* handle any byte blocks left */ | |
if (n) | |
do | |
*dst++ = 0; | |
while (--n); | |
} | |
/* | |
* Startup routine for embedded application ... | |
*/ | |
asm void _startup(void) | |
{ | |
/* disable interrupts */ | |
move.w #0x2700,sr | |
/* Pre-init SP, in case memory for stack is not valid it should be setup using | |
MEMORY_INIT before __initialize_hardware is called | |
*/ | |
lea __SP_AFTER_RESET,a7; | |
/* initialize memory */ | |
MEMORY_INIT | |
/* initialize any hardware specific issues */ | |
jsr __initialize_hardware | |
/* setup the stack pointer */ | |
lea _SP_INIT,a7 | |
/* setup A6 dummy stackframe */ | |
movea.l #0,a6 | |
link a6,#0 | |
/* setup A5 */ | |
lea _SDA_BASE,a5 | |
/* zero initialize the .bss section */ | |
lea _END_BSS, a0 | |
lea _START_BSS, a1 | |
suba.l a1, a0 | |
move.l a0, d0 | |
beq __skip_bss__ | |
lea _START_BSS, a0 | |
/* call clear_mem with base pointer in a0 and size in d0 */ | |
jsr clear_mem | |
__skip_bss__: | |
/* zero initialize the .sbss section */ | |
lea _END_SBSS, a0 | |
lea _START_SBSS, a1 | |
suba.l a1, a0 | |
move.l a0, d0 | |
beq __skip_sbss__ | |
lea _START_SBSS, a0 | |
/* call clear_mem with base pointer in a0 and size in d0 */ | |
jsr clear_mem | |
__skip_sbss__: | |
/* copy all ROM sections to their RAM locations ... */ | |
#if SUPPORT_ROM_TO_RAM | |
/* | |
* _S_romp is a null terminated array of | |
* typedef struct RomInfo { | |
* unsigned long Source; | |
* unsigned long Target; | |
* unsigned long Size; | |
* } RomInfo; | |
* | |
* Watch out if you're rebasing using _PICPID_DELTA | |
*/ | |
lea _S_romp, a0 | |
move.l a0, d0 | |
beq __skip_rom_copy__ | |
jsr __copy_rom_sections_to_ram | |
#else | |
/* | |
* There's a single block to copy from ROM to RAM, perform | |
* the copy directly without using the __S_romp structure | |
*/ | |
lea __DATA_RAM, a0 | |
lea __DATA_ROM, a1 | |
cmpa a0,a1 | |
beq __skip_rom_copy__ | |
move.l #__DATA_END, d0 | |
sub.l a0, d0 | |
jsr __copy_rom_section | |
#endif | |
__skip_rom_copy__: | |
/* call C++ static initializers (__sinit__(void)) */ | |
jsr __call_static_initializers | |
jsr __initialize_system | |
/* call main(int, char **) */ | |
pea __argv | |
clr.l -(sp) /* clearing a long is ok since it's caller cleanup */ | |
jsr main | |
addq.l #8, sp | |
unlk a6 | |
/* now call exit(0) to terminate the application */ | |
clr.l -(sp) | |
jsr exit | |
addq.l #4, sp | |
/* should never reach here but just in case */ | |
illegal | |
rts | |
/* exit will never return */ | |
__argv: | |
dc.l 0 | |
} | |