1 /*****************************************************
\r
2 start12.c - standard startup code
\r
3 The startup code may be optimized to special user requests
\r
4 ----------------------------------------------------
\r
5 Copyright (c) Metrowerks, Basel, Switzerland
\r
9 Note: ROM libraries are not implemented in this startup code
\r
10 Note: C++ destructors of global objects are NOT yet supported in the HIWARE Object File Format.
\r
11 To use this feature, please build your application with the ELF object file format.
\r
12 *****************************************************/
\r
15 #include "start12.h"
\r
17 /* Macros to control how the startup code handles the COP: */
\r
18 /* #define _DO_FEED_COP_ : do feed the COP */
\r
19 /* #define _DO_ENABLE_COP_: do enable the COP */
\r
20 /* #define _DO_DISABLE_COP_: disable the COP */
\r
21 /* Without defining any of these, the startup code does NOT handle the COP */
\r
23 #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 */
\r
24 struct _tagStartup _startupData; /* read-only: */
\r
25 /* _startupData is allocated in ROM and */
\r
26 /* initialized by the linker */
\r
27 #pragma DATA_SEG DEFAULT
\r
28 #if defined(FAR_DATA)
\r
29 #include "non_bank.sgm"
\r
30 /* the init function must be in non banked memory if banked variables are used */
\r
31 /* because _SET_PAGE is called, which may change any page register. */
\r
36 void _SET_PAGE(void); /* the inline assembler needs a prototype */
\r
37 /* this is a runtime routine with a special */
\r
38 /* calling convention, dont use it in c code! */
\r
39 static void Init(void);
\r
40 static void Fini(void);
\r
42 #include "default.sgm"
\r
43 #if defined( __BANKED__) || defined(__LARGE__)
\r
44 static void __far Init(void);
\r
45 static void __far Fini(void);
\r
46 #endif /* defined( __BANKED__) || defined(__LARGE__) */
\r
47 #endif /* FAR_DATA */
\r
50 /* define value and bits for Windef Register */
\r
52 #define WINDEF (*(volatile unsigned char*) 0x37)
\r
53 #if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)
\r
54 #define __ENABLE_PPAGE__ 0x40
\r
56 #define __ENABLE_PPAGE__ 0x0
\r
58 #if defined(__DPAGE__)
\r
59 #define __ENABLE_DPAGE__ 0x80
\r
61 #define __ENABLE_DPAGE__ 0x0
\r
63 #if defined(__EPAGE__)
\r
64 #define __ENABLE_EPAGE__ 0x20
\r
66 #define __ENABLE_EPAGE__ 0x0
\r
68 #endif /* HC812A4 */
\r
70 #ifdef _HCS12_SERIALMON
\r
71 /* for Monitor based software remap the RAM & EEPROM to adhere
\r
72 to EB386. Edit RAM and EEPROM sections in PRM file to match these. */
\r
73 #define ___INITRM (*(volatile unsigned char *) 0x0010)
\r
74 #define ___INITRG (*(volatile unsigned char *) 0x0011)
\r
75 #define ___INITEE (*(volatile unsigned char *) 0x0012)
\r
78 #if defined(_DO_FEED_COP_)
\r
79 #define __FEED_COP_IN_HLI() } __asm movb #0x55, _COP_RST_ADR; __asm movb #0xAA, _COP_RST_ADR; __asm {
\r
81 #define __FEED_COP_IN_HLI() /* do nothing */
\r
84 #if !defined(FAR_DATA) && (defined( __BANKED__) || defined(__LARGE__))
\r
85 static void __far Init(void)
\r
87 static void Init(void)
\r
90 /* purpose: 1) zero out RAM-areas where data is allocated */
\r
91 /* 2) copy initialization data from ROM to RAM */
\r
92 /* 3) call global constructors in C++ */
\r
93 /* called from: _Startup, LibInits */
\r
96 #if defined(__HIWARE_OBJECT_FILE_FORMAT__) && defined(__LARGE__)
\r
97 LDX _startupData.pZeroOut:1 ; in the large memory model in the HIWARE format, pZeroOut is a 24 bit pointer
\r
99 LDX _startupData.pZeroOut ; *pZeroOut
\r
101 LDY _startupData.nofZeroOuts ; nofZeroOuts
\r
102 BEQ CopyDown ; if nothing to zero out
\r
104 NextZeroOut: PSHY ; save nofZeroOuts
\r
106 LDAB 1,X+ ; load page of destination address
\r
107 LDY 2,X+ ; load offset of destination address
\r
108 __PIC_JSR(_SET_PAGE) ; sets the page in the correct page register
\r
109 #else /* FAR_DATA */
\r
110 LDY 2,X+ ; start address and advance *pZeroOut (X = X+4)
\r
111 #endif /* FAR_DATA */
\r
112 LDD 2,X+ ; byte count
\r
113 #ifdef __OPTIMIZE_FOR_SIZE__ /* -os, default */
\r
114 NextWord: CLR 1,Y+ ; clear memory byte
\r
115 __FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */
\r
116 DBNE D, NextWord ; dec byte count
\r
118 LSRD ; /2 and save bit 0 in the carry
\r
121 LoopClrW: STX 2,Y+ ; Word-Clear
\r
122 __FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */
\r
125 BCC LastClr ; handle last byte
\r
129 PULY ; restore nofZeroOuts
\r
130 DEY ; dec nofZeroOuts
\r
133 #ifdef __ELF_OBJECT_FILE_FORMAT__
\r
134 LDX _startupData.toCopyDownBeg ; load address of copy down desc.
\r
136 LDX _startupData.toCopyDownBeg:2 ; load address of copy down desc.
\r
139 LDD 2,X+ ; size of init-data -> D
\r
140 BEQ funcInits ; end of copy down desc.
\r
142 PSHD ; save counter
\r
143 LDAB 1,X+ ; load destination page
\r
144 LDY 2,X+ ; destination address
\r
145 __PIC_JSR(_SET_PAGE) ; sets the destinations page register
\r
146 PULD ; restore counter
\r
147 #else /* FAR_DATA */
\r
148 LDY 2,X+ ; load destination address
\r
149 #endif /* FAR_DATA */
\r
151 #ifdef __OPTIMIZE_FOR_SIZE__ /* -os, default */
\r
152 Copy: MOVB 1,X+,1,Y+ ; move a byte from ROM to the data area
\r
153 __FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */
\r
154 DBNE D,Copy ; copy-byte loop
\r
156 LSRD ; /2 and save bit 0 in the carry
\r
157 Copy: MOVW 2,X+,2,Y+ ; move a word from ROM to the data area
\r
158 __FEED_COP_IN_HLI() ; feed the COP if necessary /*lint !e505 !e522 asm code */
\r
159 DBNE D,Copy ; copy-word loop
\r
160 BCC NextBlock ; handle last byte?
\r
161 MOVB 1,X+,1,Y+ ; copy the last byte
\r
164 funcInits: ; call of global construtors is only in c++ necessary
\r
165 #if defined(__cplusplus)
\r
166 #if defined(__ELF_OBJECT_FILE_FORMAT__)
\r
167 #if defined( __BANKED__) || defined(__LARGE__)
\r
168 LDY _startupData.nofInitBodies; load number of cpp.
\r
169 BEQ done ; if cppcount == 0, goto done
\r
170 LDX _startupData.initBodies ; load address of first module to initialize
\r
172 LEAX 3,X ; increment to next init
\r
173 PSHX ; save address of next function to initialize
\r
174 PSHY ; save cpp counter
\r
175 CALL [-3,X] ; use double indirect call to load the page register also
\r
176 PULY ; restore cpp counter
\r
177 PULX ; restore actual address
\r
178 DEY ; decrement cpp counter
\r
180 #else /* defined( __BANKED__) || defined(__LARGE__) */
\r
182 LDD _startupData.nofInitBodies; load number of cpp.
\r
183 BEQ done ; if cppcount == 0, goto done
\r
184 LDX _startupData.initBodies ; load address of first module to initialize
\r
186 LDY 2,X+ ; load address of first module to initialize
\r
188 PSHX ; save actual address
\r
189 JSR 0,Y ; call initialization function
\r
190 PULX ; restore actual address
\r
191 PULD ; restore cpp counter
\r
193 #endif /* defined( __BANKED__) || defined(__LARGE__) */
\r
194 #else /* __ELF_OBJECT_FILE_FORMAT__ */
\r
195 LDX _startupData.mInits ; load address of first module to initialize
\r
196 #if defined( __BANKED__) || defined(__LARGE__)
\r
197 nextInit: LDY 3,X+ ; load address of initialization function
\r
198 BEQ done ; stop when address == 0
\r
199 ; in common environments the offset of a function is never 0, so this test could be avoided
\r
200 #ifdef __InitFunctionsMayHaveOffset0__
\r
201 BRCLR -1,X, done, 0xff ; stop when address == 0
\r
202 #endif /* __InitFunctionsMayHaveOffset0__ */
\r
203 PSHX ; save address of next function to initialize
\r
204 CALL [-3,X] ; use double indirect call to load the page register also
\r
205 #else /* defined( __BANKED__) || defined(__LARGE__) */
\r
207 LDY 2,X+ ; load address of first module to initialize
\r
208 BEQ done ; stop when address of function == 0
\r
209 PSHX ; save actual address
\r
210 JSR 0,Y ; call initialization function
\r
211 #endif /* defined( __BANKED__) || defined(__LARGE__) */
\r
212 PULX ; restore actual address
\r
214 #endif /* __ELF_OBJECT_FILE_FORMAT__ */
\r
216 #endif /* __cplusplus */
\r
220 #if defined( __ELF_OBJECT_FILE_FORMAT__) && defined(__cplusplus )
\r
222 #if !defined(FAR_DATA) && (defined( __BANKED__) || defined(__LARGE__))
\r
223 static void __far Fini(void)
\r
225 static void Fini(void)
\r
228 /* purpose: 1) call global destructors in C++ */
\r
230 #if defined( __BANKED__) || defined(__LARGE__)
\r
232 LDY _startupData.nofFiniBodies; load number of cpp.
\r
233 BEQ done ; if cppcount == 0, goto done
\r
234 LDX _startupData.finiBodies ; load address of first module to finalize
\r
236 LEAX 3,X ; increment to next init
\r
237 PSHX ; save address of next function to finalize
\r
238 PSHY ; save cpp counter
\r
239 CALL [-3,X] ; use double indirect call to load the page register also
\r
240 PULY ; restore cpp counter
\r
241 PULX ; restore actual address
\r
242 DEY ; decrement cpp counter
\r
244 #else /* defined( __BANKED__) || defined(__LARGE__) */
\r
246 LDD _startupData.nofFiniBodies; load number of cpp.
\r
247 BEQ done ; if cppcount == 0, goto done
\r
248 LDX _startupData.finiBodies ; load address of first module to finalize
\r
250 LDY 2,X+ ; load address of first module to finalize
\r
252 PSHX ; save actual address
\r
253 JSR 0,Y ; call finalize function
\r
254 PULX ; restore actual address
\r
255 PULD ; restore cpp counter
\r
257 #endif /* defined( __BANKED__) || defined(__LARGE__) */
\r
264 #include "non_bank.sgm"
\r
266 #pragma MESSAGE DISABLE C12053 /* Stack-pointer change not in debugging-information */
\r
275 /* The function _Startup must be called in order to initialize global variables and to call main */
\r
276 /* You can adapt this function or call it from your startup code to implement a different startup */
\r
277 /* functionality. */
\r
279 /* You should also setup the needed IO registers as WINDEF (HC12A4 only) or the COP registers to run */
\r
282 /* to set the reset vector several ways are possible : */
\r
283 /* 1. define the function with "interrupt 0" as done below in the first case */
\r
284 /* 2. add the following line to your prm file : VECTOR ADDRESS 0xfffe _Startup */
\r
285 /* of course, even more posibilities exists */
\r
286 /* the reset vector must be set so that the application has a defined entry point */
\r
288 #define STARTUP_FLAGS_NOT_INIT_SP (1<<1)
\r
290 #if defined(__SET_RESET_VECTOR__)
\r
291 void __interrupt 0 _Startup(void) {
\r
293 void _Startup(void) {
\r
295 /* purpose: 1) initialize the stack
\r
296 2) initialize the RAM, copy down init data etc (Init)
\r
299 called from: _PRESTART-code generated by the Linker
\r
300 or directly referenced by the reset vector */
\r
301 for(;;) { /* forever: initialize the program; call the root-procedure */
\r
302 if (!(_startupData.flags&STARTUP_FLAGS_NOT_INIT_SP)) {
\r
303 /* initialize the stack pointer */
\r
304 INIT_SP_FROM_STARTUP_DESC(); /*lint !e522 asm code */ /* HLI macro definition in hidef.h */
\r
307 #ifdef _HCS12_SERIALMON
\r
308 /* for Monitor based software remap the RAM & EEPROM to adhere
\r
309 to EB386. Edit RAM and EEPROM sections in PRM file to match these. */
\r
310 ___INITRG = 0x00; /* lock registers block to 0x0000 */
\r
311 ___INITRM = 0x39; /* lock Ram to end at 0x3FFF */
\r
312 ___INITEE = 0x09; /* lock EEPROM block to end at 0x0fff */
\r
315 /* Here user defined code could be inserted, the stack could be used */
\r
316 #if defined(_DO_DISABLE_COP_)
\r
320 /* Example : Set up WinDef Register to allow Paging */
\r
321 #ifdef HC812A4 /* HC12 A4 derivative needs WINDEF to configure which pages are available */
\r
322 #if (__ENABLE_EPAGE__ != 0 || __ENABLE_DPAGE__ != 0 || __ENABLE_PPAGE__ != 0)
\r
323 WINDEF= __ENABLE_EPAGE__ | __ENABLE_DPAGE__ | __ENABLE_PPAGE__;
\r
326 Init(); /* zero out, copy down, call constructors */
\r
327 /* Here user defined code could be inserted, all global variables are initilized */
\r
328 #if defined(_DO_ENABLE_COP_)
\r
333 (*_startupData.main)();
\r
335 /* call destructors. Only done when this file is compiled as C++ and for the ELF object file format */
\r
336 /* the HIWARE object file format does not support this */
\r
337 #if defined( __ELF_OBJECT_FILE_FORMAT__) && defined(__cplusplus )
\r
341 } /* end loop forever */
\r