* device/lib/pic16/startup/crt0.c,
[fw/sdcc] / device / lib / pic16 / startup / crt0iz.c
1 /*
2  * crt0iz.c - SDCC pic16 port runtime start code with
3  *            initialisation and clear RAM
4  *
5  * Converted for SDCC and pic16 port
6  * by Vangelis Rokas (vrokas@otenet.gr)
7  *
8  * based on Microchip MPLAB-C18 startup files
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2, or (at your option) any
13  * later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  *
24  * In other words, you are welcome to use, share and improve this program.
25  * You are forbidden to forbid anyone else to use, share and improve
26  * what you give them.   Help stamp out software-hoarding!
27  *
28  * $Id$
29  */
30
31 extern stack_end;
32 extern TBLPTRU;
33 extern TBLPTRH;
34 extern TBLPTRL;
35 extern FSR0L;
36 extern FSR0H;
37 extern TABLAT;
38 extern POSTINC0;
39 extern POSTDEC0;
40
41 #if 1
42 /* global variable for forcing gplink to add _cinit section */
43 char __uflags = 0;
44 #endif
45
46 /* external reference to the user's main routine */
47 extern void main (void);
48
49 void _entry (void) __naked __interrupt 0;
50 void _startup (void) __naked;
51 void _do_cinit (void) __naked;
52
53 /* Access bank selector. */
54 #define a 0
55
56
57 /*
58  * entry function, placed at interrupt vector 0 (RESET)
59  */
60 void _entry (void) __naked __interrupt 0
61 {
62   __asm
63     goto    __startup
64   __endasm;
65 }
66
67 void _startup (void) __naked
68 {
69   __asm
70     ; Initialize the stack pointer
71     lfsr    1, _stack_end
72     lfsr    2, _stack_end
73
74     ; 1st silicon does not do this on POR
75     clrf    _TBLPTRU, a
76
77     ; Initialize the flash memory access configuration.
78     ; This is harmless for non-flash devices, so we do it on all parts.
79     bsf     0xa6, 7, a      ; EECON1.EEPGD = 1, TBLPTR accesses program memory
80     bcf     0xa6, 6, a      ; EECON1.CFGS  = 0, TBLPTR accesses program memory
81   __endasm;
82
83   /* cleanup the RAM */
84   __asm
85     ; Load FSR0 with top of RAM.
86     setf    _FSR0L, a
87     movlw   0x0e
88     movwf   _FSR0H, a
89
90     ; Place 0xff at address 0x00 as a sentinel.
91     setf    0x00, a
92
93 clear_loop:
94     clrf    _POSTDEC0, a
95     movf    0x00, w, a
96     bnz     clear_loop
97   __endasm;
98
99   /* Initialize global and/or static variables. */
100   _do_cinit();
101
102   /* Call the main routine. */
103   main();
104
105   __asm
106 lockup:
107     ; Returning from main will lock up.
108     bra     lockup
109   __endasm;
110 }
111
112
113 /* the cinit table will be filled by the linker */
114 extern __code struct {
115   unsigned short num_init;
116   struct {
117     unsigned long from;
118     unsigned long to;
119     unsigned long size;
120   } entries[1];
121 } cinit;
122
123
124 #define TBLRDPOSTINC    tblrd*+
125
126 #define prom            0x00            /* 0x00 0x01 0x02*/
127 #define curr_byte       0x03            /* 0x03 0x04 */
128 #define curr_entry      0x05            /* 0x05 0x06 */
129 #define data_ptr        0x07            /* 0x07 0x08 0x09 */
130
131 /* the variable initialisation routine */
132 void _do_cinit (void) __naked
133 {
134   /*
135    * access registers 0x00 - 0x09 are not saved in this function
136    */
137   __asm
138     ; TBLPTR = &cinit
139     movlw   low(_cinit)
140     movwf   _TBLPTRL, a
141     movlw   high(_cinit)
142     movwf   _TBLPTRH, a
143     movlw   upper(_cinit)
144     movwf   _TBLPTRU, a
145
146     ; curr_entry = cinit.num_init
147     TBLRDPOSTINC
148     movf    _TABLAT, w, a
149     movwf   curr_entry, a
150
151     TBLRDPOSTINC
152     movf    _TABLAT, w, a
153     movwf   curr_entry + 1, a
154
155     ; while (curr_entry)
156     movf    curr_entry, w, a
157 test:
158     bnz     cont1
159     movf    curr_entry + 1, w, a
160     bz      done
161
162 cont1:
163     ; Count down so we only have to look up the data in _cinit once.
164
165     ; At this point we know that TBLPTR points to the top of the current
166     ; entry in _cinit, so we can just start reading the from, to, and
167     ; size values.
168
169     ; read the source address low
170     TBLRDPOSTINC
171     movf    _TABLAT, w, a
172     movwf   prom, a
173
174     ; source address high
175     TBLRDPOSTINC
176     movf    _TABLAT, w, a
177     movwf   prom + 1, a
178
179     ; source address upper
180     TBLRDPOSTINC
181     movf    _TABLAT, w, a
182     movwf   prom + 2, a
183
184     ; skip a byte since it is stored as a 32bit int
185     TBLRDPOSTINC
186
187     ; read the destination address directly into FSR0
188     ; destination address low
189     TBLRDPOSTINC
190     movf    _TABLAT, w, a
191     movwf   _FSR0L, a
192
193     ; destination address high
194     TBLRDPOSTINC
195     movf    _TABLAT, w, a
196     movwf   _FSR0H, a
197
198     ; skip two bytes since it is stored as a 32bit int
199     TBLRDPOSTINC
200     TBLRDPOSTINC
201
202     ; read the size of data to transfer to destination address
203     TBLRDPOSTINC
204     movf    _TABLAT, w, a
205     movwf   curr_byte, a
206
207     TBLRDPOSTINC
208     movf    _TABLAT, w, a
209     movwf   curr_byte + 1, a
210
211     ; skip two bytes since it is stored as a 32bit int
212     TBLRDPOSTINC
213     TBLRDPOSTINC
214
215     ;  prom = data_ptr->from;
216     ;  FSR0 = data_ptr->to;
217     ;  curr_byte = (unsigned short) data_ptr->size;
218
219     ; the table pointer now points to the next entry. Save it
220     ; off since we will be using the table pointer to do the copying
221     ; for the entry
222
223     ; data_ptr = TBLPTR
224     movff   _TBLPTRL, data_ptr
225     movff   _TBLPTRH, data_ptr + 1
226     movff   _TBLPTRU, data_ptr + 2
227
228     ; now assign the source address to the table pointer
229     ; TBLPTR = prom
230     movff   prom, _TBLPTRL
231     movff   prom + 1, _TBLPTRH
232     movff   prom + 2, _TBLPTRU
233
234     ; while (curr_byte)
235     movf    curr_byte, w, a
236 copy_loop:
237     bnz     copy_one_byte
238     movf    curr_byte + 1, w, a
239     bz      done_copying
240
241 copy_one_byte:
242     TBLRDPOSTINC
243     movf    _TABLAT, w, a
244     movwf   _POSTINC0, a
245
246     ; decrement byte counter
247     decf    curr_byte, f, a
248     bc      copy_loop
249     decf    curr_byte + 1, f, a
250     bra     copy_one_byte
251
252 done_copying:
253     ; restore the table pointer for the next entry
254     ; TBLPTR = data_ptr
255     movff   data_ptr, _TBLPTRL
256     movff   data_ptr + 1, _TBLPTRH
257     movff   data_ptr + 2, _TBLPTRU
258
259     ; decrement entry counter
260     decf    curr_entry, f, a
261     bc      test
262     decf    curr_entry + 1, f, a
263     bra     cont1
264
265     ; emit done label
266 done:
267     return
268   __endasm;
269 }
270