/***************************************************** | |
start12.c - standard startup code | |
The startup code may be optimized to special user requests | |
---------------------------------------------------- | |
Copyright (c) Metrowerks, Basel, Switzerland | |
All rights reserved | |
Do not modify! | |
Note: ROM libraries are not implemented in this startup code | |
Note: C++ destructors of global objects are NOT yet supported in the HIWARE Object File Format. | |
To use this feature, please build your application with the ELF object file format. | |
*****************************************************/ | |
#include "hidef.h" | |
#include "start12.h" | |
/* Macros to control how the startup code handles the COP: */ | |
/* #define _DO_FEED_COP_ : do feed the COP */ | |
/* #define _DO_ENABLE_COP_: do enable the COP */ | |
/* #define _DO_DISABLE_COP_: disable the COP */ | |
/* Without defining any of these, the startup code does NOT handle the COP */ | |
#pragma DATA_SEG __NEAR_SEG STARTUP_DATA /* _startupData can be accessed using 16 bit accesses. This is needed because it contains the stack top, and without stack, far data cannot be accessed */ | |
struct _tagStartup _startupData; /* read-only: */ | |
/* _startupData is allocated in ROM and */ | |
/* initialized by the linker */ | |
#pragma DATA_SEG DEFAULT | |
#if defined(FAR_DATA) | |
#include "non_bank.sgm" | |
/* the init function must be in non banked memory if banked variables are used */ | |
/* because _SET_PAGE is called, which may change any page register. */ | |
#ifdef __cplusplus | |
extern "C" | |
#endif | |
void _SET_PAGE(void); /* the inline assembler needs a prototype */ | |
/* this is a runtime routine with a special */ | |
/* calling convention, dont use it in c code! */ | |
static void Init(void); | |
static void Fini(void); | |
#else | |
#include "default.sgm" | |
#if defined( __BANKED__) || defined(__LARGE__) | |
static void __far Init(void); | |
static void __far Fini(void); | |
#endif /* defined( __BANKED__) || defined(__LARGE__) */ | |
#endif /* FAR_DATA */ | |
/* define value and bits for Windef Register */ | |
#ifdef HC812A4 | |
#define WINDEF (*(volatile unsigned char*) 0x37) | |
#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__) | |
#define __ENABLE_PPAGE__ 0x40 | |
#else | |
#define __ENABLE_PPAGE__ 0x0 | |
#endif | |
#if defined(__DPAGE__) | |
#define __ENABLE_DPAGE__ 0x80 | |
#else | |
#define __ENABLE_DPAGE__ 0x0 | |
#endif | |
#if defined(__EPAGE__) | |
#define __ENABLE_EPAGE__ 0x20 | |
#else | |
#define __ENABLE_EPAGE__ 0x0 | |
#endif | |
#endif /* HC812A4 */ | |
#ifdef _HCS12_SERIALMON | |
/* for Monitor based software remap the RAM & EEPROM to adhere | |
to EB386. Edit RAM and EEPROM sections in PRM file to match these. */ | |
#define ___INITRM (*(volatile unsigned char *) 0x0010) | |
#define ___INITRG (*(volatile unsigned char *) 0x0011) | |
#define ___INITEE (*(volatile unsigned char *) 0x0012) | |
#endif | |
#if defined(_DO_FEED_COP_) | |
#define __FEED_COP_IN_HLI() } __asm movb #0x55, _COP_RST_ADR; __asm movb #0xAA, _COP_RST_ADR; __asm { | |
#else | |
#define __FEED_COP_IN_HLI() /* do nothing */ | |
#endif | |
#if !defined(FAR_DATA) && (defined( __BANKED__) || defined(__LARGE__)) | |
static void __far Init(void) | |
#else | |
static void Init(void) | |
#endif | |
{ | |
/* purpose: 1) zero out RAM-areas where data is allocated */ | |
/* 2) copy initialization data from ROM to RAM */ | |
/* 3) call global constructors in C++ */ | |
/* called from: _Startup, LibInits */ | |
__asm { | |
ZeroOut: | |
#if defined(__HIWARE_OBJECT_FILE_FORMAT__) && defined(__LARGE__) | |
LDX _startupData.pZeroOut:1 ; in the large memory model in the HIWARE format, pZeroOut is a 24 bit pointer | |
#else | |
LDX _startupData.pZeroOut ; *pZeroOut | |
#endif | |
LDY _startupData.nofZeroOuts ; nofZeroOuts | |
BEQ CopyDown ; if nothing to zero out | |
NextZeroOut: PSHY ; save nofZeroOuts | |
#ifdef FAR_DATA | |
LDAB 1,X+ ; load page of destination address | |
LDY 2,X+ ; load offset of destination address | |
__PIC_JSR(_SET_PAGE) ; sets the page in the correct page register | |
#else /* FAR_DATA */ | |
LDY 2,X+ ; start address and advance *pZeroOut (X = X+4) | |
#endif /* FAR_DATA */ | |
LDD 2,X+ ; byte count | |
#ifdef __OPTIMIZE_FOR_SIZE__ /* -os, default */ | |
NextWord: CLR 1,Y+ ; clear memory byte | |
__FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */ | |
DBNE D, NextWord ; dec byte count | |
#else | |
LSRD ; /2 and save bit 0 in the carry | |
PSHX | |
LDX #0 | |
LoopClrW: STX 2,Y+ ; Word-Clear | |
__FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */ | |
DBNE D, LoopClrW | |
PULX | |
BCC LastClr ; handle last byte | |
CLR 1,Y+ | |
LastClr: | |
#endif | |
PULY ; restore nofZeroOuts | |
DEY ; dec nofZeroOuts | |
BNE NextZeroOut | |
CopyDown: | |
#ifdef __ELF_OBJECT_FILE_FORMAT__ | |
LDX _startupData.toCopyDownBeg ; load address of copy down desc. | |
#else | |
LDX _startupData.toCopyDownBeg:2 ; load address of copy down desc. | |
#endif | |
NextBlock: | |
LDD 2,X+ ; size of init-data -> D | |
BEQ funcInits ; end of copy down desc. | |
#ifdef FAR_DATA | |
PSHD ; save counter | |
LDAB 1,X+ ; load destination page | |
LDY 2,X+ ; destination address | |
__PIC_JSR(_SET_PAGE) ; sets the destinations page register | |
PULD ; restore counter | |
#else /* FAR_DATA */ | |
LDY 2,X+ ; load destination address | |
#endif /* FAR_DATA */ | |
#ifdef __OPTIMIZE_FOR_SIZE__ /* -os, default */ | |
Copy: MOVB 1,X+,1,Y+ ; move a byte from ROM to the data area | |
__FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */ | |
DBNE D,Copy ; copy-byte loop | |
#else | |
LSRD ; /2 and save bit 0 in the carry | |
Copy: MOVW 2,X+,2,Y+ ; move a word from ROM to the data area | |
__FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */ | |
DBNE D,Copy ; copy-word loop | |
BCC NextBlock ; handle last byte? | |
MOVB 1,X+,1,Y+ ; copy the last byte | |
#endif | |
BRA NextBlock | |
funcInits: ; call of global construtors is only in c++ necessary | |
#if defined(__cplusplus) | |
#if defined(__ELF_OBJECT_FILE_FORMAT__) | |
#if defined( __BANKED__) || defined(__LARGE__) | |
LDY _startupData.nofInitBodies; load number of cpp. | |
BEQ done ; if cppcount == 0, goto done | |
LDX _startupData.initBodies ; load address of first module to initialize | |
nextInit: | |
LEAX 3,X ; increment to next init | |
PSHX ; save address of next function to initialize | |
PSHY ; save cpp counter | |
CALL [-3,X] ; use double indirect call to load the page register also | |
PULY ; restore cpp counter | |
PULX ; restore actual address | |
DEY ; decrement cpp counter | |
BNE nextInit | |
#else /* defined( __BANKED__) || defined(__LARGE__) */ | |
LDD _startupData.nofInitBodies; load number of cpp. | |
BEQ done ; if cppcount == 0, goto done | |
LDX _startupData.initBodies ; load address of first module to initialize | |
nextInit: | |
LDY 2,X+ ; load address of first module to initialize | |
PSHD | |
PSHX ; save actual address | |
JSR 0,Y ; call initialization function | |
PULX ; restore actual address | |
PULD ; restore cpp counter | |
DBNE D, nextInit | |
#endif /* defined( __BANKED__) || defined(__LARGE__) */ | |
#else /* __ELF_OBJECT_FILE_FORMAT__ */ | |
LDX _startupData.mInits ; load address of first module to initialize | |
#if defined( __BANKED__) || defined(__LARGE__) | |
nextInit: LDY 3,X+ ; load address of initialization function | |
BEQ done ; stop when address == 0 | |
; in common environments the offset of a function is never 0, so this test could be avoided | |
#ifdef __InitFunctionsMayHaveOffset0__ | |
BRCLR -1,X, done, 0xff ; stop when address == 0 | |
#endif /* __InitFunctionsMayHaveOffset0__ */ | |
PSHX ; save address of next function to initialize | |
CALL [-3,X] ; use double indirect call to load the page register also | |
#else /* defined( __BANKED__) || defined(__LARGE__) */ | |
nextInit: | |
LDY 2,X+ ; load address of first module to initialize | |
BEQ done ; stop when address of function == 0 | |
PSHX ; save actual address | |
JSR 0,Y ; call initialization function | |
#endif /* defined( __BANKED__) || defined(__LARGE__) */ | |
PULX ; restore actual address | |
BRA nextInit | |
#endif /* __ELF_OBJECT_FILE_FORMAT__ */ | |
done: | |
#endif /* __cplusplus */ | |
} | |
} | |
#if defined( __ELF_OBJECT_FILE_FORMAT__) && defined(__cplusplus ) | |
#if !defined(FAR_DATA) && (defined( __BANKED__) || defined(__LARGE__)) | |
static void __far Fini(void) | |
#else | |
static void Fini(void) | |
#endif | |
{ | |
/* purpose: 1) call global destructors in C++ */ | |
__asm { | |
#if defined( __BANKED__) || defined(__LARGE__) | |
LDY _startupData.nofFiniBodies; load number of cpp. | |
BEQ done ; if cppcount == 0, goto done | |
LDX _startupData.finiBodies ; load address of first module to finalize | |
nextInit2: | |
LEAX 3,X ; increment to next init | |
PSHX ; save address of next function to finalize | |
PSHY ; save cpp counter | |
CALL [-3,X] ; use double indirect call to load the page register also | |
PULY ; restore cpp counter | |
PULX ; restore actual address | |
DEY ; decrement cpp counter | |
BNE nextInit2 | |
#else /* defined( __BANKED__) || defined(__LARGE__) */ | |
LDD _startupData.nofFiniBodies; load number of cpp. | |
BEQ done ; if cppcount == 0, goto done | |
LDX _startupData.finiBodies ; load address of first module to finalize | |
nextInit2: | |
LDY 2,X+ ; load address of first module to finalize | |
PSHD | |
PSHX ; save actual address | |
JSR 0,Y ; call finalize function | |
PULX ; restore actual address | |
PULD ; restore cpp counter | |
DBNE D, nextInit2 | |
#endif /* defined( __BANKED__) || defined(__LARGE__) */ | |
done:; | |
} | |
} | |
#endif | |
#include "non_bank.sgm" | |
#pragma MESSAGE DISABLE C12053 /* Stack-pointer change not in debugging-information */ | |
#pragma NO_FRAME | |
#pragma NO_ENTRY | |
#pragma NO_EXIT | |
#ifdef __cplusplus | |
extern "C" | |
#endif | |
/* The function _Startup must be called in order to initialize global variables and to call main */ | |
/* You can adapt this function or call it from your startup code to implement a different startup */ | |
/* functionality. */ | |
/* You should also setup the needed IO registers as WINDEF (HC12A4 only) or the COP registers to run */ | |
/* on hardware */ | |
/* to set the reset vector several ways are possible : */ | |
/* 1. define the function with "interrupt 0" as done below in the first case */ | |
/* 2. add the following line to your prm file : VECTOR ADDRESS 0xfffe _Startup */ | |
/* of course, even more posibilities exists */ | |
/* the reset vector must be set so that the application has a defined entry point */ | |
#define STARTUP_FLAGS_NOT_INIT_SP (1<<1) | |
#if defined(__SET_RESET_VECTOR__) | |
void __interrupt 0 _Startup(void) { | |
#else | |
void _Startup(void) { | |
#endif | |
/* purpose: 1) initialize the stack | |
2) initialize the RAM, copy down init data etc (Init) | |
3) call main; | |
parameters: NONE | |
called from: _PRESTART-code generated by the Linker | |
or directly referenced by the reset vector */ | |
for(;;) { /* forever: initialize the program; call the root-procedure */ | |
if (!(_startupData.flags&STARTUP_FLAGS_NOT_INIT_SP)) { | |
/* initialize the stack pointer */ | |
INIT_SP_FROM_STARTUP_DESC(); /*lint !e522 asm code */ /* HLI macro definition in hidef.h */ | |
} | |
#ifdef _HCS12_SERIALMON | |
/* for Monitor based software remap the RAM & EEPROM to adhere | |
to EB386. Edit RAM and EEPROM sections in PRM file to match these. */ | |
___INITRG = 0x00; /* lock registers block to 0x0000 */ | |
___INITRM = 0x39; /* lock Ram to end at 0x3FFF */ | |
___INITEE = 0x09; /* lock EEPROM block to end at 0x0fff */ | |
#endif | |
/* Here user defined code could be inserted, the stack could be used */ | |
#if defined(_DO_DISABLE_COP_) | |
_DISABLE_COP(); | |
#endif | |
/* Example : Set up WinDef Register to allow Paging */ | |
#ifdef HC812A4 /* HC12 A4 derivative needs WINDEF to configure which pages are available */ | |
#if (__ENABLE_EPAGE__ != 0 || __ENABLE_DPAGE__ != 0 || __ENABLE_PPAGE__ != 0) | |
WINDEF= __ENABLE_EPAGE__ | __ENABLE_DPAGE__ | __ENABLE_PPAGE__; | |
#endif | |
#endif | |
Init(); /* zero out, copy down, call constructors */ | |
/* Here user defined code could be inserted, all global variables are initilized */ | |
#if defined(_DO_ENABLE_COP_) | |
_ENABLE_COP(1); | |
#endif | |
/* call main() */ | |
(*_startupData.main)(); | |
/* call destructors. Only done when this file is compiled as C++ and for the ELF object file format */ | |
/* the HIWARE object file format does not support this */ | |
#if defined( __ELF_OBJECT_FILE_FORMAT__) && defined(__cplusplus ) | |
Fini(); | |
#endif | |
} /* end loop forever */ | |
} |