* src/pic16/device.c (Pics16[]): moved device descriptions to devices.inc
[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 "main.h"
39 #include "pcode.h"
40 #include "ralloc.h"
41 #include "device.h"
42
43
44 static PIC16_device Pics16[] = {
45 /* Device descriptions are now generated by scripts.
46  * For simplicities sake we just include them here.
47  * Manual overrides may be inserted on top of devices.inc
48  * or right here BEFORE inclusion of devices.inc. */
49 #include "devices.inc"
50 };
51
52 static int num_of_supported_PICS = sizeof(Pics16)/sizeof(PIC16_device);
53
54 stats_t statistics = { 0, 0, 0, 0 };
55
56 #define DEFAULT_PIC "452"
57
58 PIC16_device *pic16=NULL;
59 unsigned int stackPos = 0;
60 unsigned int stackLen = 0;
61
62 extern regs* newReg(short type, short pc_type, int rIdx, char *name, int size, int alias, operand *refop);
63
64 void pic16_setMaxRAM(int size)
65 {
66         pic16->maxRAMaddress = size;
67         stackPos = pic16->RAMsize-1;
68
69         if (pic16->maxRAMaddress < 0) {
70                 fprintf(stderr, "invalid \"#pragma maxram 0x%x\" setting\n",
71                         pic16->maxRAMaddress);
72           return;
73         }
74 }
75
76 extern char *iComments2;
77
78 void pic16_dump_equates(FILE *of, set *equs)
79 {
80   regs *r;
81
82         r = setFirstItem(equs);
83         if(!r)return;
84         
85         fprintf(of, "%s", iComments2);
86         fprintf(of, ";\tEquates to used internal registers\n");
87         fprintf(of, "%s", iComments2);
88         
89         for(; r; r = setNextItem(equs)) {
90                 fprintf(of, "%s\tequ\t0x%02x\n", r->name, r->address);
91         }
92 }
93
94
95 void pic16_dump_access(FILE *of, set *section)
96 {
97   regs *r;
98
99         r = setFirstItem(section);
100         if(!r)return;
101         
102         fprintf(of, "%s", iComments2);
103         fprintf(of, ";\tAccess bank symbols\n");
104         fprintf(of, "%s", iComments2);
105         
106         fprintf(of, "\tudata_acs\n");
107         for(; r; r = setNextItem(section)) {
108                 fprintf(of, "%s\tres\t%d\n", r->name, r->size);
109                 statistics.adsize += r->size;
110         }
111 }
112
113
114 int regCompare(const void *a, const void *b)
115 {
116   const regs *const *i = a;
117   const regs *const *j = b;
118
119         /* sort primarily by the address */
120         if( (*i)->address > (*j)->address)return 1;
121         if( (*i)->address < (*j)->address)return -1;
122         
123         /* and secondarily by size */
124         /* register size sorting may have strange results use with care */
125         if( (*i)->size > (*j)->size)return 1;
126         if( (*i)->size < (*j)->size)return -1;
127         
128         /* finally if in same address and same size sort by name */
129         return (strcmp( (*i)->name, (*j)->name));
130
131   return 0;
132 }
133
134 int symCompare(const void *a, const void *b)
135 {
136   const symbol *const *i = a;
137   const symbol *const *j = b;
138
139         /* sort primarily by the address */
140         if( SPEC_ADDR((*i)->etype) > SPEC_ADDR((*j)->etype))return 1;
141         if( SPEC_ADDR((*i)->etype) < SPEC_ADDR((*j)->etype))return -1;
142         
143         /* and secondarily by size */
144         /* register size sorting may have strange results use with care */
145         if( getSize((*i)->etype) > getSize((*j)->etype))return 1;
146         if( getSize((*i)->etype) < getSize((*j)->etype))return -1;
147
148         /* finally if in same address and same size sort by name */
149         return (strcmp( (*i)->rname, (*j)->rname));
150
151   return 0;
152 }
153
154 void pic16_dump_usection(FILE *of, set *section, int fix)
155 {
156   static int abs_usection_no=0;
157   static unsigned int usection_no=0;
158   regs *r, *rprev;
159   unsigned int init_addr, i;
160   regs **rlist;
161   regs *r1;
162
163         /* put all symbols in an array */
164         if (!elementsInSet(section)) return;
165         rlist = Safe_calloc(elementsInSet(section), sizeof(regs *));
166         r = rlist[0]; i = 0;
167         for(rprev = setFirstItem(section); rprev; rprev = setNextItem(section)) {
168                 rlist[i] = rprev; i++;
169         }
170         
171         if(!i) {
172                 if(rlist)Safe_free(rlist);
173           return;
174         }
175
176         /* sort symbols according to their address */
177         qsort(rlist, i  /*elementsInSet(section)*/, sizeof(regs *), regCompare);
178         
179         if(!fix) {
180
181 #define EMIT_SINGLE_UDATA_SECTION       0
182 #if EMIT_SINGLE_UDATA_SECTION
183                 fprintf(of, "\n\n\tudata\n");
184                 for(r = setFirstItem(section); r; r = setNextItem(section)) {
185                         fprintf(of, "%s\tres\t%d\n", r->name, r->size);
186                         statistics.udsize += r->size;
187                 }
188 #else
189                 for(r = setFirstItem(section); r; r = setNextItem(section)) {
190                         //fprintf(of, "\nudata_%s_%s\tudata\n", moduleName, r->name);
191                         fprintf(of, "\nudata_%s_%u\tudata\n", moduleName, usection_no++);
192                         fprintf(of, "%s\tres\t%d\n", r->name, r->size);
193                         statistics.udsize += r->size;
194                 }
195 #endif
196         } else {
197           unsigned int j=0;
198           int deb_addr=0;
199
200                 rprev = NULL;
201                 init_addr = rlist[j]->address;
202                 deb_addr = init_addr;
203                 fprintf(of, "\n\nustat_%s_%02d\tudata\t0X%04X\n", moduleName, abs_usection_no++, init_addr);
204         
205                 for(j=0;j<i;j++) {
206                         r = rlist[j];
207                         if(j < i-1)r1 = rlist[j+1]; else r1 = NULL;
208                         
209                         init_addr = r->address;
210                         deb_addr = init_addr;
211                         
212                         if((rprev && (init_addr > (rprev->address + rprev->size)))) {
213                                 fprintf(of, "\n\nustat_%s_%02d\tudata\t0X%04X\n", moduleName, abs_usection_no++, init_addr);
214                         }
215
216                         if(r1 && (init_addr == r1->address)) {
217                                 fprintf(of, "\n%s\tres\t0\n", r->name);
218                         } else {
219                                 fprintf(of, "%s\tres\t%d\n", r->name, r->size);
220                                 deb_addr += r->size;
221                                 statistics.udsize += r->size;
222                         }
223                         
224                         rprev = r;
225                 }
226         }
227         Safe_free(rlist);
228 }
229
230 void pic16_dump_gsection(FILE *of, set *sections)
231 {
232   regs *r;
233   sectName *sname;
234
235         for(sname = setFirstItem(sections); sname; sname = setNextItem(sections)) {
236                 if(!strcmp(sname->name, "access"))continue;
237                 fprintf(of, "\n\n%s\tudata\n", sname->name);
238
239                 for(r=setFirstItem(sname->regsSet); r; r=setNextItem(sname->regsSet)) {
240 #if 0
241                         fprintf(stderr, "%s:%d emitting variable %s for section %s (%p)\n", __FILE__, __LINE__,
242                                 r->name, sname->name, sname);
243 #endif
244                         fprintf(of, "%s\tres\t%d\n", r->name, r->size);
245                         statistics.udsize += r->size;
246                 }
247         }
248 }
249
250
251 /* forward declaration */
252 void pic16_printIval(symbol * sym, sym_link * type, initList * ilist, char ptype, void *p);
253 extern void pic16_pCodeConstString(char *name, char *value);
254
255 void pic16_dump_isection(FILE *of, set *section, int fix)
256 {
257   static int abs_isection_no=0;
258   symbol *s, *sprev;
259   unsigned int init_addr, i;
260   symbol **slist;
261
262         /* put all symbols in an array */
263         if (!elementsInSet(section)) return;
264         slist = Safe_calloc(elementsInSet(section), sizeof(symbol *));
265         s = slist[0]; i = 0;
266         for(sprev = setFirstItem(section); sprev; sprev = setNextItem(section)) {
267                 slist[i] = sprev; i++;
268         }
269         
270         if(!i) {
271                 if(slist)Safe_free(slist);
272           return;
273         }
274
275         /* sort symbols according to their address */
276         qsort(slist, i, sizeof(symbol *), symCompare);
277         
278         pic16_initDB();
279
280         if(!fix) {
281                 fprintf(of, "\n\n\tidata\n");
282                 for(s = setFirstItem(section); s; s = setNextItem(section)) {
283
284                         if(s->ival) {
285                                 fprintf(of, "%s", s->rname);
286                                 pic16_printIval(s, s->type, s->ival, 'f', (void *)of);
287                                 pic16_flushDB('f', (void *)of);
288                         } else {
289                                 if (IS_ARRAY (s->type) && IS_CHAR (s->type->next)
290                                         && SPEC_CVAL (s->etype).v_char) {
291
292 //                                      fprintf(stderr, "%s:%d printing code string from %s\n", __FILE__, __LINE__, s->rname);
293                                         pic16_pCodeConstString(s->rname , SPEC_CVAL (s->etype).v_char);
294                                 } else {
295                                         assert(0);
296                                 }
297                         }
298                                 
299                 }
300         } else {
301           unsigned int j=0;
302           symbol *s1;
303           
304                 sprev = NULL;
305                 init_addr = SPEC_ADDR(slist[j]->etype);
306                 fprintf(of, "\n\nistat_%s_%02d\tidata\t0X%04X\n", moduleName, abs_isection_no++, init_addr);
307         
308                 for(j=0;j<i;j++) {
309                         s = slist[j];
310                         if(j < i-1)s1 = slist[j+1]; else s1 = NULL;
311                         
312                         init_addr = SPEC_ADDR(s->etype);
313
314                         if(sprev && (init_addr > (SPEC_ADDR(sprev->etype) + getSize(sprev->etype)))) {
315                                 fprintf(of, "\nistat_%s_%02d\tidata\t0X%04X\n", moduleName, abs_isection_no++, init_addr);
316                         }
317
318                         if(s->ival) {
319                                 fprintf(of, "%s", s->rname);
320                                 pic16_printIval(s, s->type, s->ival, 'f', (void *)of);
321                                 pic16_flushDB('f', (void *)of);
322                         } else {
323                                 if (IS_ARRAY (s->type) && IS_CHAR (s->type->next)
324                                         && SPEC_CVAL (s->etype).v_char) {
325
326 //                                      fprintf(stderr, "%s:%d printing code string from %s\n", __FILE__, __LINE__, s->rname);
327                                         pic16_pCodeConstString(s->rname , SPEC_CVAL (s->etype).v_char);
328                                 } else {
329                                         assert(0);
330                                 }
331                         }
332
333
334                         sprev = s;
335                 }
336         }
337         Safe_free(slist);
338 }
339
340
341 void pic16_dump_int_registers(FILE *of, set *section)
342 {
343   regs *r, *rprev;
344   int i;
345   regs **rlist;
346
347         /* put all symbols in an array */
348         if (!elementsInSet(section)) return;
349         rlist = Safe_calloc(elementsInSet(section), sizeof(regs *));
350         r = rlist[0]; i = 0;
351         for(rprev = setFirstItem(section); rprev; rprev = setNextItem(section)) {
352                 rlist[i] = rprev; i++;
353         }
354
355         /* sort symbols according to their address */
356         qsort(rlist, elementsInSet(section), sizeof(regs *), regCompare);
357         
358         if(!i) {
359                 if(rlist)Safe_free(rlist);
360           return;
361         }
362         
363         fprintf(of, "\n\n; Internal registers\n");
364         
365         fprintf(of, "%s\tudata_ovr\t0x0000\n", ".registers");
366         for(r = setFirstItem(section); r; r = setNextItem(section)) {
367                 fprintf(of, "%s\tres\t%d\n", r->name, r->size);
368                 statistics.intsize += r->size;
369         }
370
371         Safe_free(rlist);
372 }
373
374
375 #ifdef WORDS_BIGENDIAN
376   #define _ENDIAN(x)  (3-x)
377 #else
378   #define _ENDIAN(x)  (x)
379 #endif
380
381 #define BYTE_IN_LONG(x,b) ((x>>(8*_ENDIAN(b)))&0xff)
382
383
384 /*-----------------------------------------------------------------*
385  *  void pic16_list_valid_pics(int ncols, int list_alias)
386  *
387  * Print out a formatted list of valid PIC devices
388  *
389  * ncols - number of columns in the list.
390  *
391  * list_alias - if non-zero, print all of the supported aliases
392  *              for a device (e.g. F84, 16F84, etc...)
393  *-----------------------------------------------------------------*/
394 void pic16_list_valid_pics(int ncols, int list_alias)
395 {
396   int col,longest;
397   int i,j,k,l;
398
399   if(list_alias)
400     list_alias = sizeof(Pics16[0].name) / sizeof(Pics16[0].name[0]);
401
402   /* decrement the column number if it's greater than zero */
403   ncols = (ncols > 1) ? ncols-1 : 4;
404
405   /* Find the device with the longest name */
406   for(i=0,longest=0; i<num_of_supported_PICS; i++) {
407     for(j=0; j<=list_alias; j++) {
408       k = strlen(Pics16[i].name[j]);
409       if(k>longest)
410         longest = k;
411     }
412   }
413
414   col = 0;
415
416   for(i=0;  i < num_of_supported_PICS; i++) {
417     j = 0;
418     do {
419
420       fprintf(stderr,"%s", Pics16[i].name[j]);
421       if(col<ncols) {
422         l = longest + 2 - strlen(Pics16[i].name[j]);
423         for(k=0; k<l; k++)
424           fputc(' ',stderr);
425
426         col++;
427
428       } else {
429         fputc('\n',stderr);
430         col = 0;
431       }
432
433     } while(++j<list_alias);
434
435   }
436   if(col != ncols)
437     fputc('\n',stderr);
438
439 }
440
441 /*-----------------------------------------------------------------*
442  *  
443  *-----------------------------------------------------------------*/
444 PIC16_device *pic16_find_device(char *name)
445 {
446
447   int i,j;
448
449   if(!name)
450     return NULL;
451
452   for(i = 0; i<num_of_supported_PICS; i++) {
453
454     for(j=0; j<PROCESSOR_NAMES; j++)
455       if(!STRCASECMP(Pics16[i].name[j], name) )
456         return &Pics16[i];
457   }
458
459   /* not found */
460   return NULL; 
461 }
462
463 /*-----------------------------------------------------------------*
464  *  
465  *-----------------------------------------------------------------*/
466 void pic16_init_pic(char *pic_type)
467 {
468         pic16 = pic16_find_device(pic_type);
469
470         if(!pic16) {
471                 if(pic_type)
472                         fprintf(stderr, "'%s' was not found.\n", pic_type);
473                 else
474                         fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
475
476                 fprintf(stderr,"Valid devices are:\n");
477
478                 pic16_list_valid_pics(4,0);
479                 exit(1);
480         }
481
482 //      printf("PIC processor found and initialized: %s\n", pic_type);
483         pic16_setMaxRAM( 0xfff  );
484 }
485
486 /*-----------------------------------------------------------------*
487  *  
488  *-----------------------------------------------------------------*/
489 int pic16_picIsInitialized(void)
490 {
491   if(pic16 && pic16->maxRAMaddress > 0)
492     return 1;
493
494   return 0;
495
496 }
497
498 /*-----------------------------------------------------------------*
499  *  char *pic16_processor_base_name(void) - Include file is derived from this.
500  *-----------------------------------------------------------------*/
501 char *pic16_processor_base_name(void)
502 {
503
504   if(!pic16)
505     return NULL;
506
507   return pic16->name[0];
508 }
509
510 #define DEBUG_CHECK     0
511
512 /*
513  * return 1 if register wasn't found and added, 0 otherwise
514  */
515 int checkAddReg(set **set, regs *reg)
516 {
517   regs *tmp;
518
519
520         if(!reg)return 0;
521 #if DEBUG_CHECK
522         fprintf(stderr, "%s: about to insert REGister: %s ... ", __FUNCTION__, reg->name);
523 #endif
524
525         for(tmp = setFirstItem(*set); tmp; tmp = setNextItem(*set)) {
526                 if(!strcmp(tmp->name, reg->name))break;
527         }
528         
529         if(!tmp) {
530                 addSet(set, reg);
531 #if DEBUG_CHECK
532                 fprintf(stderr, "added\n");
533 #endif
534                 return 1;
535         }
536
537 #if DEBUG_CHECK
538         fprintf(stderr, "already added\n");
539 #endif
540   return 0;
541 }
542
543 int checkAddSym(set **set, symbol *sym)
544 {
545   symbol *tmp;
546
547         if(!sym)return 0;
548 #if DEBUG_CHECK
549         fprintf(stderr, "%s: about to add SYMbol: %s ... ", __FUNCTION__, sym->name);
550 #endif
551
552         for(tmp = setFirstItem( *set ); tmp; tmp = setNextItem(*set)) {
553                 if(!strcmp(tmp->name, sym->name))break;
554         }
555         
556         if(!tmp) {
557                 addSet(set, sym);
558 #if DEBUG_CHECK
559                 fprintf(stderr, "added\n");
560 #endif
561                 return 1;
562         }
563
564 #if DEBUG_CHECK
565         fprintf(stderr, "already added\n");
566 #endif
567
568   return 0;
569 }
570
571 int checkSym(set *set, symbol *sym)
572 {
573   symbol *tmp;
574
575         if(!sym)return 0;
576         
577 #if DEUG_CHECK
578         fprintf(stderr, "%s: about to search for SYMbol: %s ... ", __FUNCTION__, sym->name);
579 #endif
580
581         for(tmp = setFirstItem( set ); tmp; tmp = setNextItem( set )) {
582                 if(!strcmp(tmp->name, sym->name))break;
583         }
584         
585         if(!tmp) {
586 #if DEBUG_CHECK
587                 fprintf(stderr, "not found\n");
588 #endif
589                 return 0;
590         }
591
592 #if DEBUG_CHECK
593         fprintf(stderr, "found\n");
594 #endif
595
596   return 1;
597 }
598
599 /*-----------------------------------------------------------------*
600  * void pic16_groupRegistersInSection - add each register to its   *
601  *      corresponding section                                      *
602  *-----------------------------------------------------------------*/
603 void pic16_groupRegistersInSection(set *regset)
604 {
605   regs *reg;
606   sectSym *ssym;
607   int docontinue=0;
608
609         for(reg=setFirstItem(regset); reg; reg = setNextItem(regset)) {
610
611 #if 0
612                 fprintf(stderr, "%s:%d group registers in section, reg: %s (used: %d, %p)\n",
613                         __FILE__, __LINE__, reg->name, reg->wasUsed, reg);
614 #endif
615                 if((reg->wasUsed
616                         && !(reg->regop && SPEC_EXTR(OP_SYM_ETYPE(reg->regop))))
617                   ) {
618                         
619                         /* avoid grouping registers that have an initial value,
620                          * they will be added later in idataSymSet */
621                         if(reg->regop && (OP_SYMBOL(reg->regop)->ival && !OP_SYMBOL(reg->regop)->level))
622                                 continue;
623
624 #if 0
625                         fprintf(stderr, "%s:%d register %s alias:%d fix:%d ival=%i level=%i code=%i\n",
626                                 __FILE__, __LINE__, reg->name, reg->alias, reg->isFixed,
627                                         (reg->regop?(OP_SYMBOL(reg->regop)->ival?1:0):-1),
628                                         (reg->regop?(OP_SYMBOL(reg->regop)->level):-1),
629                                         (reg->regop?(IS_CODE(OP_SYM_ETYPE(reg->regop))):-1) );
630 #endif
631                         
632                         docontinue=0;
633                         for(ssym=setFirstItem(sectSyms);ssym;ssym=setNextItem(sectSyms)) {
634                                 if(!strcmp(ssym->name, reg->name)) {
635 //                                      fprintf(stderr, "%s:%d section found %s (%p) with var %s\n",
636 //                                                      __FILE__, __LINE__, ssym->section->name, ssym->section, ssym->name);
637                                         if(strcmp(ssym->section->name, "access")) {
638                                                 addSet(&ssym->section->regsSet, reg);
639                                                 docontinue=1;
640                                                 break;
641                                         } else {
642                                                 docontinue=0;
643                                                 reg->accessBank = 1;
644                                                 break;
645                                         }
646                                 }
647                         }
648
649                         if(docontinue)continue;
650
651 //                      fprintf(stderr, "%s:%d reg: %s\n", __FILE__, __LINE__, reg->name);
652
653                         if(reg->alias == 0x80) {
654                                 checkAddReg(&pic16_equ_data, reg);
655                         } else
656                         if(reg->isFixed) {
657                                 checkAddReg(&pic16_fix_udata, reg);
658                         } else
659                         if(!reg->isFixed) {
660                                 if(reg->pc_type == PO_GPR_TEMP)
661                                         checkAddReg(&pic16_int_regs, reg);
662                                 else {
663                                         if(reg->accessBank) {
664                                                 if(reg->alias != 0x40)
665                                                         checkAddReg(&pic16_acs_udata, reg);
666                                         } else
667                                                 checkAddReg(&pic16_rel_udata, reg);
668                                 }
669                         }
670                 }
671         }
672 }
673
674
675
676
677
678 /*-----------------------------------------------------------------*
679  *  void pic16_assignConfigWordValue(int address, int value)
680  *
681  * All high performance RISC CPU PICs have seven config word starting
682  * at address 0x300000.
683  * This routine will assign a value to that address.
684  *
685  *-----------------------------------------------------------------*/
686 void pic16_assignConfigWordValue(int address, unsigned int value)
687 {
688   int i;
689
690         for(i=0;i<pic16->cwInfo.confAddrEnd-pic16->cwInfo.confAddrStart+1;i++) {
691                 if((address == pic16->cwInfo.confAddrStart+i)
692                   && (pic16->cwInfo.crInfo[i].mask != -1)) {
693
694 #if 0
695                         fprintf(stderr, "setting location 0x%X to value 0x%x\tmask: 0x%x\ttest: 0x%x\n",
696                                 /*address*/ pic16->cwInfo.confAddrStart+i, (~value)&0xff,
697                                         pic16->cwInfo.crInfo[i].mask,
698                                         (pic16->cwInfo.crInfo[i].mask) & (~value));
699 #endif
700
701 #if 0
702                         if((((pic16->cwInfo.crInfo[i].mask) & (~value))&0xff) != ((~value)&0xff)) {
703                                 fprintf(stderr, "%s:%d a wrong value has been given for configuration register 0x%x\n",
704                                         __FILE__, __LINE__, address);
705                                         return;
706                         }
707 #endif
708
709                         pic16->cwInfo.crInfo[i].value = value;
710                         pic16->cwInfo.crInfo[i].emit = 1;
711                         return;
712                 }
713         }
714 }
715
716 void pic16_assignIdByteValue(int address, char value)
717 {
718   int i;
719
720         for(i=0;i<pic16->idInfo.idAddrEnd-pic16->idInfo.idAddrStart+1;i++) {
721                 if(address == pic16->idInfo.idAddrStart+i) {
722                         pic16->idInfo.irInfo[i].value = value;
723                         pic16->idInfo.irInfo[i].emit = 1;
724                 }
725         }
726 }