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