* src/pic16/device.c (Pics16[]): added devices 18F2550, 18F4331,
[fw/sdcc] / device / lib / pic16 / startup / crt0i.c
1 /*
2  * crt0i.c - SDCC pic16 port runtime start code with
3  *           initialisation
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
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
82   _endasm ;
83     
84   _do_cinit();
85
86   /* Call the user's main routine */
87   main();
88
89 loop:
90   /* return from main will lock up */
91   goto loop;
92 }
93
94
95 /* the cinit table will be filled by the linker */
96 extern code struct
97 {
98   unsigned short num_init;
99   struct _init_entry {
100     unsigned long from;
101     unsigned long to;
102     unsigned long size;
103   } entries[];
104 } cinit;
105
106
107 #define TBLRDPOSTINC    tblrd*+
108
109 #define prom            0x00            /* 0x00 0x01 0x02*/
110 #define curr_byte       0x03            /* 0x03 0x04 */
111 #define curr_entry      0x05            /* 0x05 0x06 */
112 #define data_ptr        0x07            /* 0x07 0x08 0x09 */
113
114 /*
115  * static short long _do_cinit_prom;
116  * static unsigned short _do_cinit_curr_byte;
117  * static unsigned short _do_cinit_curr_entry;
118  * static short long _do_cinit_data_ptr;
119  */
120
121 /* the variable initialisation routine */
122 void _do_cinit (void) _naked
123 {
124   /*
125    * access registers 0x00 - 0x09 are not saved in this function
126    */
127   _asm
128       ; TBLPTR = &cinit
129     movlw low(_cinit)
130     movwf _TBLPTRL
131     movlw high(_cinit)
132     movwf _TBLPTRH
133     movlw upper(_cinit)
134     movwf _TBLPTRU
135         
136                   ; curr_entry = cinit.num_init
137                   ; movlb data_ptr
138     TBLRDPOSTINC
139     movf _TABLAT, w
140     movwf curr_entry
141
142     TBLRDPOSTINC
143     movf _TABLAT, w
144     movwf curr_entry+1
145
146                   ; while (curr_entry) {
147 test:
148     bnz done1
149     tstfsz curr_entry, 1
150     bra cont1
151
152 done1:
153     goto done
154
155 cont1:
156
157     ; Count down so we only have to look up the data in _cinit once. 
158
159     ; At this point we know that TBLPTR points to the top of the current 
160     ; entry in _cinit, so we can just start reading the from, to, and 
161     ; size values. 
162
163     ; read the source address low 
164     TBLRDPOSTINC
165     movf _TABLAT, w
166     movwf prom
167                 
168     ; source address high 
169     TBLRDPOSTINC
170     movf _TABLAT, w
171     movwf prom + 1
172
173     ; source address upper 
174     TBLRDPOSTINC
175     movf _TABLAT, w
176     movwf prom + 2
177
178     ; skip a byte since it is stored as a 32bit int 
179     TBLRDPOSTINC
180
181     ; read the destination address directly into FSR0 
182     ; destination address low 
183     TBLRDPOSTINC
184     movf _TABLAT, w
185     movwf _FSR0L
186
187     ; destination address high 
188     TBLRDPOSTINC
189     movf _TABLAT, w
190     movwf _FSR0H
191
192     ; skip two bytes since it is stored as a 32bit int 
193     TBLRDPOSTINC
194     TBLRDPOSTINC
195
196     ; read the destination address directly into FSR0 
197     TBLRDPOSTINC
198     movf _TABLAT, w
199     movwf curr_byte
200     
201     TBLRDPOSTINC
202     movf _TABLAT, w
203     movwf curr_byte+1
204     
205
206     ; skip two bytes since it is stored as a 32bit int 
207     TBLRDPOSTINC
208     TBLRDPOSTINC
209
210     ;  prom = data_ptr->from; 
211     ;  FSR0 = data_ptr->to; 
212     ;  curr_byte = (unsigned short) data_ptr->size; 
213
214     ; the table pointer now points to the next entry. Save it 
215     ; off since we will be using the table pointer to do the copying 
216     ; for the entry 
217   
218     ; data_ptr = TBLPTR 
219
220     movff _TBLPTRL, data_ptr
221     movff _TBLPTRH, data_ptr + 1
222     movff _TBLPTRU, data_ptr + 2
223       
224     ; now assign the source address to the table pointer 
225     ; TBLPTR = prom 
226     
227     movff prom, _TBLPTRL
228     movff prom + 1, _TBLPTRH
229     movff prom + 2, _TBLPTRU
230
231     ; do the copy loop 
232
233     ; determine if we have any more bytes to copy 
234                   ; movlb curr_byte 
235     movf curr_byte, w
236
237 copy_loop:
238     bnz copy_one_byte           ; copy_one_byte 
239     movf curr_byte + 1, w
240     bz done_copying
241
242 copy_one_byte:
243     TBLRDPOSTINC
244     movf _TABLAT, w
245     movwf _POSTINC0
246
247     ; decrement byte counter 
248     decf curr_byte, f
249     bnc copy_loop               ; copy_loop 
250     decf curr_byte + 1, f
251
252     bra copy_loop
253 done_copying:
254
255   
256     ; restore the table pointer for the next entry 
257     ; TBLPTR = data_ptr 
258     movff data_ptr, _TBLPTRL
259     movff data_ptr + 1, _TBLPTRH
260     movff data_ptr + 2, _TBLPTRU
261
262     dcfsnz curr_entry, f
263     decf curr_entry + 1, f
264
265     ; next entry...
266     ; _do_cinit_curr_entry--; 
267
268     goto test;
269
270     ; emit done label 
271 done:
272     return
273   _endasm;
274 }
275