|
|
|
|
/*
|
|
|
|
|
* CF_Startup.c - Default init/startup/termination routines for
|
|
|
|
|
* Embedded Metrowerks C++
|
|
|
|
|
*
|
|
|
|
|
* Copyright <EFBFBD> 1993-1998 Metrowerks, Inc. All Rights Reserved.
|
|
|
|
|
* Copyright <EFBFBD> 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
|
|
|
|
|
}
|
|
|
|
|
|