* src/pic16/device.h (pic16_options_t): added field use_crt,
[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  * $Id$
11  */
12
13 extern stack;
14 extern stack_end;
15
16 extern TBLPTRU;
17 extern TBLPTRH;
18 extern TBLPTRL;
19 extern FSR0L;
20 extern FSR0H;
21 extern TABLAT;
22 extern POSTINC0;
23
24 /* global variable for forcing gplink to add _cinit section */
25 char __uflags = 0;
26
27 /* external reference to the user's main routine */
28 extern void main (void);
29
30 /* prototype for the startup function */
31 void _entry (void) _naked interrupt 0;
32 void _startup (void);
33
34 /* prototype for the initialized data setup */
35 void _do_cinit (void);
36
37
38 /*
39  * entry function, placed at interrupt vector 0 (RESET)
40  */
41
42 void _entry (void) _naked interrupt 0
43 {
44   _asm goto __startup _endasm;
45 }
46
47
48 void _startup (void)
49 {
50         _asm
51                 // Initialize the stack pointer
52                 lfsr 1, _stack_end
53                 lfsr 2, _stack_end
54                 clrf _TBLPTRU, 0        // 1st silicon doesn't do this on POR
55     
56                 // initialize the flash memory access configuration. this is harmless
57                 // for non-flash devices, so we do it on all parts.
58                 bsf 0xa6, 7, 0
59                 bcf 0xa6, 6, 0
60
61         _endasm ;
62     
63         _do_cinit();
64
65         /* Call the user's main routine */
66         main ();
67
68 loop:
69         /* return from main will lock up */
70         goto loop;
71 }
72
73
74 /* the cinit table will be filled by the linker */
75 extern code struct
76 {
77   unsigned short num_init;
78   struct _init_entry {
79     unsigned long from;
80     unsigned long to;
81     unsigned long size;
82   } entries[];
83 } cinit;
84
85
86 #define tblrdpostinc    tblrd*+
87
88 /* the variable initialisation routine */
89 void _do_cinit (void)
90 {
91   /*
92    * we'll make the assumption in the following code that these statics
93    * will be allocated into the same bank.
94    */
95   static short long prom;
96   static unsigned short curr_byte;
97   static unsigned short curr_entry;
98   static short long data_ptr;
99
100
101         /* TBLPTR = &cinit */
102         _asm
103                 movlw low(_cinit)
104                 movwf _TBLPTRL, 0
105                 movlw high(_cinit)
106                 movwf _TBLPTRH, 0
107                 movlw upper(_cinit)
108                 movwf _TBLPTRU, 0
109         _endasm;
110
111         
112         /* curr_entry = cinit.num_init */
113         _asm
114                 movlb __do_cinit_data_ptr_1_1
115                 tblrdpostinc
116                 movf _TABLAT, 0, 0
117                 movwf __do_cinit_curr_entry_1_1, 1
118                 tblrdpostinc
119                 movf _TABLAT, 0, 0
120                 movwf __do_cinit_curr_entry_1_1+1, 1
121         _endasm;
122
123
124         //while (curr_entry) {
125         _asm
126 test:
127         bnz done1
128         tstfsz __do_cinit_curr_entry_1_1, 1
129         bra cont1
130
131 done1:
132         goto done
133
134 cont1:
135         _endasm;
136
137
138       /* Count down so we only have to look up the data in _cinit
139        * once.
140        *
141        * At this point we know that TBLPTR points to the top of the current
142        * entry in _cinit, so we can just start reading the from, to, and
143        * size values.
144        */
145         _asm
146                 
147                 /* read the source address low */
148                 tblrdpostinc
149                 movf _TABLAT, 0, 0
150                 movwf __do_cinit_prom_1_1, 1
151                 
152                 /* source address high */
153                 tblrdpostinc
154                 movf _TABLAT, 0, 0
155                 movwf __do_cinit_prom_1_1 + 1, 1
156
157                 /* source address upper */
158                 tblrdpostinc
159                 movf _TABLAT, 0, 0
160                 movwf __do_cinit_prom_1_1 + 2, 1
161
162                 /* skip a byte since it's stored as a 32bit int */
163                 tblrdpostinc
164
165                 /* read the destination address directly into FSR0 */
166                 /* destination address low */
167                 tblrdpostinc
168                 movf _TABLAT, 0, 0
169                 movwf _FSR0L, 0
170
171                 /* destination address high */
172                 tblrdpostinc
173                 movf _TABLAT, 0, 0
174                 movwf _FSR0H, 0
175
176                 /* skip two bytes since it's stored as a 32bit int */
177                 tblrdpostinc
178                 tblrdpostinc
179
180                 /* read the destination address directly into FSR0 */
181                 tblrdpostinc
182                 movf _TABLAT, 0, 0
183                 movwf __do_cinit_curr_byte_1_1, 1
184                 tblrdpostinc
185                 movf _TABLAT, 0, 0
186                 movwf __do_cinit_curr_byte_1_1+1, 1
187
188                 /* skip two bytes since it's stored as a 32bit int */
189                 tblrdpostinc
190                 tblrdpostinc
191         _endasm;
192
193         //prom = data_ptr->from;
194         //FSR0 = data_ptr->to;
195         //curr_byte = (unsigned short) data_ptr->size;
196         /* the table pointer now points to the next entry. Save it
197          * off since we'll be using the table pointer to do the copying
198          * for the entry */
199   
200         /*  data_ptr = TBLPTR */
201         _asm
202                 movff _TBLPTRL, __do_cinit_data_ptr_1_1
203                 movff _TBLPTRH, __do_cinit_data_ptr_1_1 + 1
204                 movff _TBLPTRU, __do_cinit_data_ptr_1_1 + 2
205         _endasm;
206   
207       
208         /* now assign the source address to the table pointer */
209         /*  TBLPTR = prom */
210         _asm
211                 movff __do_cinit_prom_1_1, _TBLPTRL
212                 movff __do_cinit_prom_1_1 + 1, _TBLPTRH
213                 movff __do_cinit_prom_1_1 + 2, _TBLPTRU
214         _endasm;
215
216         /* do the copy loop */
217         _asm
218
219                 /* determine if we have any more bytes to copy */
220                 movlb __do_cinit_curr_byte_1_1
221                 movf __do_cinit_curr_byte_1_1, 1, 1
222 copy_loop:
223                 bnz copy_one_byte // copy_one_byte
224                 movf __do_cinit_curr_byte_1_1 + 1, 1, 1
225                 bz done_copying
226
227 copy_one_byte:
228                 tblrdpostinc
229                 movf _TABLAT, 0, 0
230                 movwf _POSTINC0, 0
231
232                 /* decrement byte counter */
233                 decf __do_cinit_curr_byte_1_1, 1, 1
234                 bnc copy_loop // copy_loop
235                 decf __do_cinit_curr_byte_1_1 + 1, 1, 1
236
237                 bra copy_loop
238 done_copying:
239         _endasm;
240   
241         /* restore the table pointer for the next entry */
242         /*  TBLPTR = data_ptr */
243         _asm
244                 movff __do_cinit_data_ptr_1_1, _TBLPTRL
245                 movff __do_cinit_data_ptr_1_1 + 1, _TBLPTRH
246                 movff __do_cinit_data_ptr_1_1 + 2, _TBLPTRU
247         _endasm;
248
249   
250         /* next entry... */
251         curr_entry--;
252
253         _asm
254                 goto test;
255
256         /* emit done label */
257 done:
258         _endasm;
259 }
260