/* * 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 }