* src/pic16/device.c (Pics16[]): added devices 18F2550, 18F4331,
[fw/sdcc] / device / lib / pic16 / startup / crt0iz.c
1 /*
2  * crt0iz.c - SDCC pic16 port runtime start code with
3  *            initialisation and RAM memory zero
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;
32 extern stack_end;
33
34 extern TBLPTRU;
35 extern TBLPTRH;
36 extern TBLPTRL;
37 extern FSR0L;
38 extern FSR0H;
39 extern TABLAT;
40 extern POSTINC0;
41 extern POSTDEC0;
42
43 #if 1
44 /* global variable for forcing gplink to add _cinit section */
45 char __uflags = 0;
46 #endif
47
48 /* external reference to the user's main routine */
49 extern void main (void);
50
51 /* prototype for the startup function */
52 void _entry (void) _naked interrupt 0;
53 void _startup (void) _naked;
54
55 /* prototype for the initialized data setup */
56 void _do_cinit (void) _naked;
57
58
59 /*
60  * entry function, placed at interrupt vector 0 (RESET)
61  */
62
63 void _entry (void) _naked interrupt 0
64 {
65   _asm goto __startup _endasm;
66 }
67
68
69 void _startup (void) _naked
70 {
71   _asm
72     // Initialize the stack pointer
73     lfsr 1, _stack_end
74     lfsr 2, _stack_end
75     clrf _TBLPTRU, 0    // 1st silicon doesn't do this on POR
76     
77     // initialize the flash memory access configuration. this is harmless
78     // for non-flash devices, so we do it on all parts.
79     bsf 0xa6, 7, 0
80     bcf 0xa6, 6, 0
81   _endasm ;
82     
83   /* cleanup the RAM */
84   _asm
85     /* load FSR0 with top of RAM memory */
86         ; movlw 0xff
87         ; movwf _FSR0L, 0
88     setf _FSR0L
89     movlw 0x0e
90     movwf _FSR0H, 0
91                 
92     /* place a 1 at address 0x00, as a marker 
93      * we haven't reached yet to it */
94         ; movlw 1
95         ; movwf 0x00, 0
96     setf 0x00
97                 
98     /* load WREG with zero */
99     movlw 0x00
100                 
101 clear_loop:
102     movwf _POSTDEC0
103     movf 0x00, w
104     bnz clear_loop
105   _endasm ;
106
107   _do_cinit();
108
109   /* Call the user's main routine */
110   main();
111
112 loop:
113   /* return from main will lock up */
114   goto loop;
115 }
116
117
118 /* the cinit table will be filled by the linker */
119 extern code struct
120 {
121   unsigned short num_init;
122   struct _init_entry {
123     unsigned long from;
124     unsigned long to;
125     unsigned long size;
126   } entries[];
127 } cinit;
128
129
130 #define TBLRDPOSTINC    tblrd*+
131
132 #define prom            0x00            /* 0x00 0x01 0x02*/
133 #define curr_byte       0x03            /* 0x03 0x04 */
134 #define curr_entry      0x05            /* 0x05 0x06 */
135 #define data_ptr        0x07            /* 0x07 0x08 0x09 */
136
137 /*
138  * static short long _do_cinit_prom;
139  * static unsigned short _do_cinit_curr_byte;
140  * static unsigned short _do_cinit_curr_entry;
141  * static short long _do_cinit_data_ptr;
142  */
143
144 /* the variable initialisation routine */
145 void _do_cinit (void) _naked
146 {
147   /*
148    * access registers 0x00 - 0x09 are not saved in this function
149    */
150
151   _asm
152       ; TBLPTR = &cinit
153     movlw low(_cinit)
154     movwf _TBLPTRL
155     movlw high(_cinit)
156     movwf _TBLPTRH
157     movlw upper(_cinit)
158     movwf _TBLPTRU
159         
160                   ; curr_entry = cinit.num_init
161                   ; movlb data_ptr
162     TBLRDPOSTINC
163     movf _TABLAT, w
164     movwf curr_entry
165
166     TBLRDPOSTINC
167     movf _TABLAT, w
168     movwf curr_entry+1
169
170                   ; while (curr_entry) {
171 test:
172     bnz done1
173     tstfsz curr_entry, 1
174     bra cont1
175
176 done1:
177     goto done
178
179 cont1:
180
181     ; Count down so we only have to look up the data in _cinit once. 
182
183     ; At this point we know that TBLPTR points to the top of the current 
184     ; entry in _cinit, so we can just start reading the from, to, and 
185     ; size values. 
186
187     ; read the source address low 
188     TBLRDPOSTINC
189     movf _TABLAT, w
190     movwf prom
191                 
192     ; source address high 
193     TBLRDPOSTINC
194     movf _TABLAT, w
195     movwf prom + 1
196
197     ; source address upper 
198     TBLRDPOSTINC
199     movf _TABLAT, w
200     movwf prom + 2
201
202     ; skip a byte since it is stored as a 32bit int 
203     TBLRDPOSTINC
204
205     ; read the destination address directly into FSR0 
206     ; destination address low 
207     TBLRDPOSTINC
208     movf _TABLAT, w
209     movwf _FSR0L
210
211     ; destination address high 
212     TBLRDPOSTINC
213     movf _TABLAT, w
214     movwf _FSR0H
215
216     ; skip two bytes since it is stored as a 32bit int 
217     TBLRDPOSTINC
218     TBLRDPOSTINC
219
220     ; read the destination address directly into FSR0 
221     TBLRDPOSTINC
222     movf _TABLAT, w
223     movwf curr_byte
224     
225     TBLRDPOSTINC
226     movf _TABLAT, w
227     movwf curr_byte+1
228     
229
230     ; skip two bytes since it is stored as a 32bit int 
231     TBLRDPOSTINC
232     TBLRDPOSTINC
233
234     ;  prom = data_ptr->from; 
235     ;  FSR0 = data_ptr->to; 
236     ;  curr_byte = (unsigned short) data_ptr->size; 
237
238     ; the table pointer now points to the next entry. Save it 
239     ; off since we will be using the table pointer to do the copying 
240     ; for the entry 
241   
242     ; data_ptr = TBLPTR 
243
244     movff _TBLPTRL, data_ptr
245     movff _TBLPTRH, data_ptr + 1
246     movff _TBLPTRU, data_ptr + 2
247       
248     ; now assign the source address to the table pointer 
249     ; TBLPTR = prom 
250     
251     movff prom, _TBLPTRL
252     movff prom + 1, _TBLPTRH
253     movff prom + 2, _TBLPTRU
254
255     ; do the copy loop 
256
257     ; determine if we have any more bytes to copy 
258                   ; movlb curr_byte 
259     movf curr_byte, w
260
261 copy_loop:
262     bnz copy_one_byte           ; copy_one_byte 
263     movf curr_byte + 1, w
264     bz done_copying
265
266 copy_one_byte:
267     TBLRDPOSTINC
268     movf _TABLAT, w
269     movwf _POSTINC0
270
271     ; decrement byte counter 
272     decf curr_byte, f
273     bnc copy_loop               ; copy_loop 
274     decf curr_byte + 1, f
275
276     bra copy_loop
277 done_copying:
278
279   
280     ; restore the table pointer for the next entry 
281     ; TBLPTR = data_ptr 
282     movff data_ptr, _TBLPTRL
283     movff data_ptr + 1, _TBLPTRH
284     movff data_ptr + 2, _TBLPTRU
285
286
287     dcfsnz curr_entry, f
288     decf curr_entry + 1, f
289
290     ; next entry...
291     ; _do_cinit_curr_entry--; 
292
293     goto test;
294
295     ; emit done label 
296 done:
297     return
298   _endasm;
299 }
300