* doc/sdccman.lyx: removed PIC16 from PIC16 Port Specific Options,
[fw/sdcc] / src / pic16 / device.c
1 /*-------------------------------------------------------------------------
2
3   device.c - Accomodates subtle variations in PIC16 devices
4
5    Written By -  Scott Dattalo scott@dattalo.com
6    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
7
8    This program is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23
24 /*
25         VR - Began writing code to make PIC16 C source files independent from
26         the header file (created by the inc2h.pl)
27
28         - adding maximum RAM memory into PIC_Device structure
29
30 */
31
32 #include <stdio.h>
33
34 #include "common.h"   // Include everything in the SDCC src directory
35 #include "newalloc.h"
36
37
38 #include "pcode.h"
39 #include "ralloc.h"
40 #include "device.h"
41
42
43 static PIC16_device Pics16[] = {
44   {
45     {"p18f242", "18f242", "pic18f242", "f242"},         // aliases
46     0,
47     0x300,                                              // bank mask
48     0x300,                                              // RAMsize
49     0
50   },
51
52   {
53     {"p18f252", "18f252", "pic18f252", "f252"},         // aliases
54     0,
55     0x600,                                              // bank mask
56     0x600,                                              // RAMsize
57     0
58   },
59
60   {
61     {"p18f442", "18f442", "pic18f442", "f442"},         // aliases
62     0,
63     0x300,                                              // bank mask
64     0x300,                                              // RAMsize
65     0
66   },
67
68   {
69     {"p18f452", "18f452", "pic18f452", "f452"},         // aliases
70     0,
71     0x600,                                              // bank mask
72     0x600,                                              // RAMsize
73     0
74   },
75
76   {
77     {"p18f248", "18f248", "pic18f248", "f248"},         // aliases
78     0,
79     0x300,                                              // bank mask
80     0x300,                                              // RAMsize
81     0
82   },
83
84   {
85     {"p18f258", "18f258", "pic18f258", "f258"},         // aliases
86     0,
87     0x600,                                              // bank mask
88     0x600,                                              // RAMsize
89     0
90   },
91
92   {
93     {"p18f448", "18f448", "pic18f448", "f448"},         // aliases
94     0,
95     0x300,                                              // bank mask
96     0x300,                                              // RAMsize
97     0
98   },
99
100   {
101     {"p18f458", "18f458", "pic18f458", "f458"},         // aliases
102     0,
103     0x600,                                              // bank mask
104     0x600,                                              // RAMsize
105     0
106   },
107
108   {
109     {"p18f6520", "18f6520", "pic18f6520", "f6520"},     // aliases
110     0,
111     0x800,                                              // bank mask
112     0x800,                                              // RAMsize
113     1
114   },
115
116   {
117     {"p18f6620", "18f6620", "pic18f6620", "f6620"},     // aliases
118     0,
119     0xf00,                                              // bank mask
120     0xf00,                                              // RAMsize
121     1
122   },
123   {
124     {"p18f6680", "18f6680", "pic18f6680", "f6680"},     // aliases
125     0,
126     0xc00,                                              // bank mask
127     0xc00,                                              // RAMsize
128     1
129   },
130   {
131     {"p18f6720", "18f6720", "pic18f6720", "f6720"},     // aliases
132     0,
133     0xf00,                                              // bank mask
134     0xf00,                                              // RAMsize
135     1
136   },
137   {
138     {"p18f8520", "18f8520", "pic18f8520", "f8520"},     // aliases
139     0,
140     0x800,                                              // bank mask
141     0x800,                                              // RAMsize
142     1
143   },
144   {
145     {"p18f8620", "18f8620", "pic18f8620", "f8620"},     // aliases
146     0,
147     0xf00,                                              // bank mask
148     0xf00,                                              // RAMsize
149     1
150   },
151   {
152     {"p18f8680", "18f8680", "pic18f8680", "f8680"},     // aliases
153     0,
154     0xc00,                                              // bank mask
155     0x800,                                              // RAMsize
156     1
157   },
158   {
159     {"p18f8720", "18f8720", "pic18f8720", "f8720"},     // aliases
160     0,
161     0xf00,                                              // bank mask
162     0xf00,                                              // RAMsize
163     1
164   },
165
166 };
167
168 static int num_of_supported_PICS = sizeof(Pics16)/sizeof(PIC16_device);
169
170 #define DEFAULT_PIC "452"
171
172 PIC16_device *pic16=NULL;
173
174 #define DEFAULT_CONFIG_BYTE 0xff
175
176 #define CONFIG1H_WORD_ADDRESS 0x300001
177 #define DEFAULT_CONFIG1H_WORD DEFAULT_CONFIG_BYTE
178
179 #define CONFIG2L_WORD_ADDRESS 0x300002
180 #define DEFAULT_CONFIG2L_WORD DEFAULT_CONFIG_BYTE
181
182 #define CONFIG2H_WORD_ADDRESS 0x300003
183 #define DEFAULT_CONFIG2H_WORD DEFAULT_CONFIG_BYTE
184
185 #define CONFIG3H_WORD_ADDRESS 0x300005
186 #define DEFAULT_CONFIG3H_WORD DEFAULT_CONFIG_BYTE
187
188 #define CONFIG4L_WORD_ADDRESS 0x300006
189 #define DEFAULT_CONFIG4L_WORD DEFAULT_CONFIG_BYTE
190
191 #define CONFIG5L_WORD_ADDRESS 0x300008
192 #define DEFAULT_CONFIG5L_WORD DEFAULT_CONFIG_BYTE
193
194 #define CONFIG5H_WORD_ADDRESS 0x300009
195 #define DEFAULT_CONFIG5H_WORD DEFAULT_CONFIG_BYTE
196
197 #define CONFIG6L_WORD_ADDRESS 0x30000a
198 #define DEFAULT_CONFIG6L_WORD DEFAULT_CONFIG_BYTE
199
200 #define CONFIG6H_WORD_ADDRESS 0x30000b
201 #define DEFAULT_CONFIG6H_WORD DEFAULT_CONFIG_BYTE
202
203 #define CONFIG7L_WORD_ADDRESS 0x30000c
204 #define DEFAULT_CONFIG7L_WORD DEFAULT_CONFIG_BYTE
205
206 #define CONFIG7H_WORD_ADDRESS 0x30000d
207 #define DEFAULT_CONFIG7H_WORD DEFAULT_CONFIG_BYTE
208
209 static unsigned int config1h_word = DEFAULT_CONFIG1H_WORD;
210 static unsigned int config2l_word = DEFAULT_CONFIG2L_WORD;
211 static unsigned int config2h_word = DEFAULT_CONFIG2H_WORD;
212 static unsigned int config3h_word = DEFAULT_CONFIG3H_WORD;
213 static unsigned int config4l_word = DEFAULT_CONFIG4L_WORD;
214 static unsigned int config5l_word = DEFAULT_CONFIG5L_WORD;
215 static unsigned int config5h_word = DEFAULT_CONFIG5H_WORD;
216 static unsigned int config6l_word = DEFAULT_CONFIG6L_WORD;
217 static unsigned int config6h_word = DEFAULT_CONFIG6H_WORD;
218 static unsigned int config7l_word = DEFAULT_CONFIG7L_WORD;
219 static unsigned int config7h_word = DEFAULT_CONFIG7H_WORD;
220
221 unsigned int stackPos = 0;
222
223 extern regs* newReg(short type, short pc_type, int rIdx, char *name, int size, int alias, operand *refop);
224
225 void pic16_setMaxRAM(int size)
226 {
227         pic16->maxRAMaddress = size;
228         stackPos = pic16->RAMsize-1;
229
230         if (pic16->maxRAMaddress < 0) {
231                 fprintf(stderr, "invalid \"#pragma maxram 0x%x\" setting\n",
232                         pic16->maxRAMaddress);
233           return;
234         }
235 }
236
237 extern char *iComments2;
238
239 void pic16_dump_equates(FILE *of, set *equs)
240 {
241   regs *r;
242
243         r = setFirstItem(equs);
244         if(!r)return;
245         
246         fprintf(of, "%s", iComments2);
247         fprintf(of, ";\tEquates to used internal registers\n");
248         fprintf(of, "%s", iComments2);
249         
250         for(; r; r = setNextItem(equs)) {
251                 fprintf(of, "%s\tequ\t0x%02x\n", r->name, r->address);
252         }
253 }
254
255
256 int regCompare(const void *a, const void *b)
257 {
258   const regs *const *i = a;
259   const regs *const *j = b;
260
261         /* sort primarily by the address */
262         if( (*i)->address > (*j)->address)return 1;
263         if( (*i)->address < (*j)->address)return -1;
264         
265         /* and secondarily by size */
266         if( (*i)->size > (*j)->size)return 1;
267         if( (*i)->size < (*j)->size)return -1;
268
269
270   return 0;
271 }
272
273 void pic16_dump_section(FILE *of, set *section, int fix)
274 {
275   static int abs_section_no=0;
276   regs *r, *rprev;
277   int init_addr, i;
278   regs **rlist;
279
280         /* put all symbols in an array */
281         rlist = Safe_calloc(elementsInSet(section), sizeof(regs *));
282         r = rlist[0]; i = 0;
283         for(rprev = setFirstItem(section); rprev; rprev = setNextItem(section)) {
284                 rlist[i] = rprev; i++;
285         }
286
287         /* sort symbols according to their address */
288         qsort(rlist, elementsInSet(section), sizeof(regs *), regCompare);
289         
290         if(!i) {
291                 if(rlist)free(rlist);
292           return;
293         }
294         
295         if(!fix) {
296                 fprintf(of, "\n\n\tudata\n");
297                 for(r = setFirstItem(section); r; r = setNextItem(section)) {
298                         fprintf(of, "%s\tres\t%d\n", r->name, r->size);
299                 }
300         } else {
301           int j=0;
302                   
303                 rprev = NULL;
304                 init_addr = rlist[j]->address;
305                 fprintf(of, "\n\nstatic_%s_%02d\tudata\t0X%04X\n", moduleName, abs_section_no++, init_addr);
306         
307                 for(j=0;j<i;j++) {
308                         r = rlist[j];
309                         init_addr = r->address;
310                         if(rprev && (init_addr != (rprev->address + rprev->size))) {
311                                 fprintf(of, "\nstatic_%s_%02d\tudata\t0X%04X\n", moduleName, abs_section_no++, init_addr);
312                         }
313
314                         fprintf(of, "%s\tres\t%d\n", r->name, r->size);
315                         rprev = r;
316                 }
317         }
318         free(rlist);
319 }
320
321 void pic16_dump_int_registers(FILE *of, set *section)
322 {
323   regs *r, *rprev;
324   int i;
325   regs **rlist;
326
327         /* put all symbols in an array */
328         rlist = Safe_calloc(elementsInSet(section), sizeof(regs *));
329         r = rlist[0]; i = 0;
330         for(rprev = setFirstItem(section); rprev; rprev = setNextItem(section)) {
331                 rlist[i] = rprev; i++;
332         }
333
334         /* sort symbols according to their address */
335         qsort(rlist, elementsInSet(section), sizeof(regs *), regCompare);
336         
337         if(!i) {
338                 if(rlist)free(rlist);
339           return;
340         }
341         
342         fprintf(of, "\n\n; Internal registers\n");
343         
344         fprintf(of, "%s\tudata_ovr\t0x0000\n", ".registers");
345         for(r = setFirstItem(section); r; r = setNextItem(section))
346                 fprintf(of, "%s\tres\t%d\n", r->name, r->size);
347
348         free(rlist);
349 }
350
351
352
353 /*-----------------------------------------------------------------*
354  *  void pic16_list_valid_pics(int ncols, int list_alias)
355  *
356  * Print out a formatted list of valid PIC devices
357  *
358  * ncols - number of columns in the list.
359  *
360  * list_alias - if non-zero, print all of the supported aliases
361  *              for a device (e.g. F84, 16F84, etc...)
362  *-----------------------------------------------------------------*/
363 void pic16_list_valid_pics(int ncols, int list_alias)
364 {
365   int col,longest;
366   int i,j,k,l;
367
368   if(list_alias)
369     list_alias = sizeof(Pics16[0].name) / sizeof(Pics16[0].name[0]);
370
371   /* decrement the column number if it's greater than zero */
372   ncols = (ncols > 1) ? ncols-1 : 4;
373
374   /* Find the device with the longest name */
375   for(i=0,longest=0; i<num_of_supported_PICS; i++) {
376     for(j=0; j<=list_alias; j++) {
377       k = strlen(Pics16[i].name[j]);
378       if(k>longest)
379         longest = k;
380     }
381   }
382
383   col = 0;
384
385   for(i=0;  i < num_of_supported_PICS; i++) {
386     j = 0;
387     do {
388
389       fprintf(stderr,"%s", Pics16[i].name[j]);
390       if(col<ncols) {
391         l = longest + 2 - strlen(Pics16[i].name[j]);
392         for(k=0; k<l; k++)
393           fputc(' ',stderr);
394
395         col++;
396
397       } else {
398         fputc('\n',stderr);
399         col = 0;
400       }
401
402     } while(++j<list_alias);
403
404   }
405   if(col != ncols)
406     fputc('\n',stderr);
407
408 }
409
410 /*-----------------------------------------------------------------*
411  *  
412  *-----------------------------------------------------------------*/
413 PIC16_device *pic16_find_device(char *name)
414 {
415
416   int i,j;
417
418   if(!name)
419     return NULL;
420
421   for(i = 0; i<num_of_supported_PICS; i++) {
422
423     for(j=0; j<PROCESSOR_NAMES; j++)
424       if(!STRCASECMP(Pics16[i].name[j], name) )
425         return &Pics16[i];
426   }
427
428   /* not found */
429   return NULL; 
430 }
431
432 /*-----------------------------------------------------------------*
433  *  
434  *-----------------------------------------------------------------*/
435 void pic16_init_pic(char *pic_type)
436 {
437         pic16 = pic16_find_device(pic_type);
438
439         if(!pic16) {
440                 if(pic_type)
441                         fprintf(stderr, "'%s' was not found.\n", pic_type);
442                 else
443                         fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
444
445                 fprintf(stderr,"Valid devices are:\n");
446
447                 pic16_list_valid_pics(4,0);
448                 exit(1);
449         }
450
451 //      printf("PIC processor found and initialized: %s\n", pic_type);
452         pic16_setMaxRAM( 0xfff  );
453 }
454
455 /*-----------------------------------------------------------------*
456  *  
457  *-----------------------------------------------------------------*/
458 int pic16_picIsInitialized(void)
459 {
460   if(pic16 && pic16->maxRAMaddress > 0)
461     return 1;
462
463   return 0;
464
465 }
466
467 /*-----------------------------------------------------------------*
468  *  char *pic16_processor_base_name(void) - Include file is derived from this.
469  *-----------------------------------------------------------------*/
470 char *pic16_processor_base_name(void)
471 {
472
473   if(!pic16)
474     return NULL;
475
476   return pic16->name[0];
477 }
478
479
480 /*
481  * return 1 if register wasn't found and added, 0 otherwise
482  */
483 int checkAddReg(set **set, regs *reg)
484 {
485   regs *tmp;
486
487
488         for(tmp = setFirstItem(*set); tmp; tmp = setNextItem(*set)) {
489                 if(!strcmp(tmp->name, reg->name))break;
490         }
491         
492         if(!tmp) {
493                 addSet(set, reg);
494                 return 1;
495         }
496
497   return 0;
498 }
499
500 /*-----------------------------------------------------------------*
501  * void pic16_groupRegistersInSection - add each register to its   *
502  *      corresponding section                                      *
503  *-----------------------------------------------------------------*/
504 void pic16_groupRegistersInSection(set *regset)
505 {
506   regs *reg;
507
508         for(reg=setFirstItem(regset); reg; reg = setNextItem(regset)) {
509                 if(reg->wasUsed
510                         && !(reg->regop && SPEC_EXTR(OP_SYM_ETYPE(reg->regop)))) {
511
512 //                      fprintf(stderr, "%s:%d register %s\n", __FILE__, __LINE__, reg->name);
513
514                         if(reg->alias) {
515                                 checkAddReg(&pic16_equ_data, reg);
516                         } else
517                         if(reg->isFixed) {
518                                 checkAddReg(&pic16_fix_udata, reg);
519                         } else
520                         if(!reg->isFixed) {
521                                 if(reg->pc_type == PO_GPR_TEMP)
522                                         checkAddReg(&pic16_int_regs, reg);
523                                 else
524                                         checkAddReg(&pic16_rel_udata, reg);
525                         }
526                 }
527         }
528 }
529
530
531
532
533
534 /*-----------------------------------------------------------------*
535  *  void pic16_assignConfigWordValue(int address, int value)
536  *
537  * All high performance RISC CPU PICs have seven config word starting
538  * at address 0x300000.
539  * This routine will assign a value to that address.
540  *
541  *-----------------------------------------------------------------*/
542
543 void pic16_assignConfigWordValue(int address, int value)
544 {
545   switch(address) {
546   case CONFIG1H_WORD_ADDRESS:
547     config1h_word = value;
548     break;
549   case CONFIG2L_WORD_ADDRESS:
550     config2l_word = value;
551     break;
552   case CONFIG2H_WORD_ADDRESS:
553     config2h_word = value;
554     break;
555   case CONFIG3H_WORD_ADDRESS:
556     config3h_word = value;
557     break;
558   case CONFIG4L_WORD_ADDRESS:
559     config4l_word = value;
560     break;
561   case CONFIG5L_WORD_ADDRESS:
562     config5l_word = value;
563     break;
564   case CONFIG5H_WORD_ADDRESS:
565     config5h_word = value;
566     break;
567   case CONFIG6L_WORD_ADDRESS:
568     config6l_word = value;
569     break;
570   case CONFIG6H_WORD_ADDRESS:
571     config6h_word = value;
572     break;
573   case CONFIG7L_WORD_ADDRESS:
574     config7l_word = value;
575     break;
576   case CONFIG7H_WORD_ADDRESS:
577     config7h_word = value;
578     break;
579   }
580
581         fprintf(stderr,"setting config word to 0x%x\n",value);
582
583 }
584 /*-----------------------------------------------------------------*
585  * int pic16_getConfigWord(int address)
586  *
587  * Get the current value of the config word.
588  *
589  *-----------------------------------------------------------------*/
590
591 int pic16_getConfigWord(int address)
592 {
593   switch(address) {
594   case CONFIG1H_WORD_ADDRESS:
595     return config1h_word;
596   case CONFIG2L_WORD_ADDRESS:
597     return config2l_word;
598   case CONFIG2H_WORD_ADDRESS:
599     return config2h_word;
600   case CONFIG3H_WORD_ADDRESS:
601     return config3h_word;
602   case CONFIG4L_WORD_ADDRESS:
603     return config4l_word;
604   case CONFIG5L_WORD_ADDRESS:
605     return config5l_word;
606   case CONFIG5H_WORD_ADDRESS:
607     return config5h_word;
608   case CONFIG6L_WORD_ADDRESS:
609     return config6l_word;
610   case CONFIG6H_WORD_ADDRESS:
611     return config6h_word;
612   case CONFIG7L_WORD_ADDRESS:
613     return config7l_word;
614   case CONFIG7H_WORD_ADDRESS:
615     return config7h_word;
616   default:
617     return 0;
618   }
619 }