Imported Upstream version 2.9.0
[debian/cc1111] / 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: crt0i.c 5183 2008-05-26 18:55:44Z tecodev $
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
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   /* Initialize global and/or static variables. */
84   _do_cinit();
85
86   /* Call the main routine. */
87   main();
88
89   __asm
90 lockup:
91     ; Returning from main will lock up.
92     bra     lockup
93   __endasm;
94 }
95
96
97 /* the cinit table will be filled by the linker */
98 extern __code struct {
99   unsigned short num_init;
100   struct {
101     unsigned long from;
102     unsigned long to;
103     unsigned long size;
104   } entries[1];
105 } cinit;
106
107
108 #define TBLRDPOSTINC    tblrd*+
109
110 #define prom            0x00            /* 0x00 0x01 0x02*/
111 #define curr_byte       0x03            /* 0x03 0x04 */
112 #define curr_entry      0x05            /* 0x05 0x06 */
113 #define data_ptr        0x07            /* 0x07 0x08 0x09 */
114
115 /* the variable initialisation routine */
116 void _do_cinit (void) __naked
117 {
118   /*
119    * access registers 0x00 - 0x09 are not saved in this function
120    */
121   __asm
122     ; TBLPTR = &cinit
123     movlw   low(_cinit)
124     movwf   _TBLPTRL, a
125     movlw   high(_cinit)
126     movwf   _TBLPTRH, a
127     movlw   upper(_cinit)
128     movwf   _TBLPTRU, a
129
130     ; curr_entry = cinit.num_init
131     TBLRDPOSTINC
132     movf    _TABLAT, w, a
133     movwf   curr_entry, a
134
135     TBLRDPOSTINC
136     movf    _TABLAT, w, a
137     movwf   curr_entry + 1, a
138
139     ; while (curr_entry)
140     movf    curr_entry, w, a
141 test:
142     bnz     cont1
143     movf    curr_entry + 1, w, a
144     bz      done
145
146 cont1:
147     ; Count down so we only have to look up the data in _cinit once.
148
149     ; At this point we know that TBLPTR points to the top of the current
150     ; entry in _cinit, so we can just start reading the from, to, and
151     ; size values.
152
153     ; read the source address low
154     TBLRDPOSTINC
155     movf    _TABLAT, w, a
156     movwf   prom, a
157
158     ; source address high
159     TBLRDPOSTINC
160     movf    _TABLAT, w, a
161     movwf   prom + 1, a
162
163     ; source address upper
164     TBLRDPOSTINC
165     movf    _TABLAT, w, a
166     movwf   prom + 2, a
167
168     ; skip a byte since it is stored as a 32bit int
169     TBLRDPOSTINC
170
171     ; read the destination address directly into FSR0
172     ; destination address low
173     TBLRDPOSTINC
174     movf    _TABLAT, w, a
175     movwf   _FSR0L, a
176
177     ; destination address high
178     TBLRDPOSTINC
179     movf    _TABLAT, w, a
180     movwf   _FSR0H, a
181
182     ; skip two bytes since it is stored as a 32bit int
183     TBLRDPOSTINC
184     TBLRDPOSTINC
185
186     ; read the size of data to transfer to destination address
187     TBLRDPOSTINC
188     movf    _TABLAT, w, a
189     movwf   curr_byte, a
190
191     TBLRDPOSTINC
192     movf    _TABLAT, w, a
193     movwf   curr_byte + 1, a
194
195     ; skip two bytes since it is stored as a 32bit int
196     TBLRDPOSTINC
197     TBLRDPOSTINC
198
199     ;  prom = data_ptr->from;
200     ;  FSR0 = data_ptr->to;
201     ;  curr_byte = (unsigned short) data_ptr->size;
202
203     ; the table pointer now points to the next entry. Save it
204     ; off since we will be using the table pointer to do the copying
205     ; for the entry
206
207     ; data_ptr = TBLPTR
208     movff   _TBLPTRL, data_ptr
209     movff   _TBLPTRH, data_ptr + 1
210     movff   _TBLPTRU, data_ptr + 2
211
212     ; now assign the source address to the table pointer
213     ; TBLPTR = prom
214     movff   prom, _TBLPTRL
215     movff   prom + 1, _TBLPTRH
216     movff   prom + 2, _TBLPTRU
217
218     ; while (curr_byte)
219     movf    curr_byte, w, a
220 copy_loop:
221     bnz     copy_one_byte
222     movf    curr_byte + 1, w, a
223     bz      done_copying
224
225 copy_one_byte:
226     TBLRDPOSTINC
227     movf    _TABLAT, w, a
228     movwf   _POSTINC0, a
229
230     ; decrement byte counter
231     decf    curr_byte, f, a
232     bc      copy_loop
233     decf    curr_byte + 1, f, a
234     bra     copy_one_byte
235
236 done_copying:
237     ; restore the table pointer for the next entry
238     ; TBLPTR = data_ptr
239     movff   data_ptr, _TBLPTRL
240     movff   data_ptr + 1, _TBLPTRH
241     movff   data_ptr + 2, _TBLPTRU
242
243     ; decrement entry counter
244     decf    curr_entry, f, a
245     bc      test
246     decf    curr_entry + 1, f, a
247     bra     cont1
248
249     ; emit done label
250 done:
251     return
252   __endasm;
253 }
254