Added the pic16 port for Martin Dubuc.
[fw/sdcc] / src / pic16 / device.c
1 /*-------------------------------------------------------------------------
2
3    device.c - Accomodates subtle variations in PIC16 devices
4    Written By -  Scott Dattalo scott@dattalo.com
5    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
6
7    This program is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 2, or (at your option) any
10    later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 -------------------------------------------------------------------------*/
21
22 #include <stdio.h>
23
24 #include "common.h"   // Include everything in the SDCC src directory
25 #include "newalloc.h"
26
27
28 #include "pcode.h"
29 #include "ralloc.h"
30 #include "device.h"
31
32 #if defined(__BORLANDC__) || defined(_MSC_VER)
33 #define STRCASECMP stricmp
34 #else
35 #define STRCASECMP strcasecmp
36 #endif
37
38 static PIC_device Pics[] = {
39   {
40     {"p18f242", "18f242", "pic18f242", "f242"},
41     (memRange *)NULL,
42     (memRange *)NULL,
43     0,
44     0x300,
45   },
46
47   {
48     {"p18f252", "18f252", "pic18f252", "f252"},
49     (memRange *)NULL,
50     (memRange *)NULL,
51     0,
52     0x600,
53   },
54
55   {
56     {"p18f442", "18f442", "pic18f442", "f442"},
57     (memRange *)NULL,
58     (memRange *)NULL,
59     0,
60     0x300,
61   },
62
63   {
64     {"p18f452", "18f452", "pic18f452", "f452"},
65     (memRange *)NULL,
66     (memRange *)NULL,
67     0,
68     0x600,
69   },
70
71 };
72
73 static int num_of_supported_PICS = sizeof(Pics)/sizeof(PIC_device);
74
75 #define DEFAULT_PIC "f452"
76
77 static PIC_device *pic=NULL;
78
79 AssignedMemory *pic16_finalMapping=NULL;
80
81 #define DEFAULT_CONFIG_BYTE 0xff
82
83 #define CONFIG1H_WORD_ADDRESS 0x300001
84 #define DEFAULT_CONFIG1H_WORD DEFAULT_CONFIG_BYTE
85
86 #define CONFIG2L_WORD_ADDRESS 0x300002
87 #define DEFAULT_CONFIG2L_WORD DEFAULT_CONFIG_BYTE
88
89 #define CONFIG2H_WORD_ADDRESS 0x300003
90 #define DEFAULT_CONFIG2H_WORD DEFAULT_CONFIG_BYTE
91
92 #define CONFIG3H_WORD_ADDRESS 0x300005
93 #define DEFAULT_CONFIG3H_WORD DEFAULT_CONFIG_BYTE
94
95 #define CONFIG4L_WORD_ADDRESS 0x300006
96 #define DEFAULT_CONFIG4L_WORD DEFAULT_CONFIG_BYTE
97
98 #define CONFIG5L_WORD_ADDRESS 0x300008
99 #define DEFAULT_CONFIG5L_WORD DEFAULT_CONFIG_BYTE
100
101 #define CONFIG5H_WORD_ADDRESS 0x300009
102 #define DEFAULT_CONFIG5H_WORD DEFAULT_CONFIG_BYTE
103
104 #define CONFIG6L_WORD_ADDRESS 0x30000a
105 #define DEFAULT_CONFIG6L_WORD DEFAULT_CONFIG_BYTE
106
107 #define CONFIG6H_WORD_ADDRESS 0x30000b
108 #define DEFAULT_CONFIG6H_WORD DEFAULT_CONFIG_BYTE
109
110 #define CONFIG7L_WORD_ADDRESS 0x30000c
111 #define DEFAULT_CONFIG7L_WORD DEFAULT_CONFIG_BYTE
112
113 #define CONFIG7H_WORD_ADDRESS 0x30000d
114 #define DEFAULT_CONFIG7H_WORD DEFAULT_CONFIG_BYTE
115
116 static unsigned int config1h_word = DEFAULT_CONFIG1H_WORD;
117 static unsigned int config2l_word = DEFAULT_CONFIG2L_WORD;
118 static unsigned int config2h_word = DEFAULT_CONFIG2H_WORD;
119 static unsigned int config3h_word = DEFAULT_CONFIG3H_WORD;
120 static unsigned int config4l_word = DEFAULT_CONFIG4L_WORD;
121 static unsigned int config5l_word = DEFAULT_CONFIG5L_WORD;
122 static unsigned int config5h_word = DEFAULT_CONFIG5H_WORD;
123 static unsigned int config6l_word = DEFAULT_CONFIG6L_WORD;
124 static unsigned int config6h_word = DEFAULT_CONFIG6H_WORD;
125 static unsigned int config7l_word = DEFAULT_CONFIG7L_WORD;
126 static unsigned int config7h_word = DEFAULT_CONFIG7H_WORD;
127
128 void pic16_addMemRange(memRange *r, int type)
129 {
130   int i;
131   int alias = r->alias;
132
133   if (pic->maxRAMaddress < 0) {
134     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
135     return;
136   }
137
138   do {
139     for (i=r->start_address; i<= r->end_address; i++) {
140       if ((i|alias) <= pic->maxRAMaddress) {
141         pic16_finalMapping[i | alias].isValid = 1;
142         pic16_finalMapping[i | alias].alias = r->alias;
143         pic16_finalMapping[i | alias].bank  = r->bank;
144         if(type) {
145           /* hack for now */
146           pic16_finalMapping[i | alias].isSFR  = 1;
147         } else {
148           pic16_finalMapping[i | alias].isSFR  = 0;
149         }
150       } else {
151         fprintf(stderr, "WARNING: %s:%s memory at 0x%x is beyond max ram = 0x%x\n",
152                 __FILE__,__FUNCTION__,(i|alias), pic->maxRAMaddress);
153       }
154     }
155
156     /* Decrement alias */
157     if (alias) {
158       alias -= ((alias & (alias - 1)) ^ alias);
159     } else {
160       alias--;
161     }
162
163   } while (alias >= 0);
164 }
165
166 void pic16_setMaxRAM(int size)
167 {
168   int i;
169   pic->maxRAMaddress = size;
170
171   if (pic->maxRAMaddress < 0) {
172     fprintf(stderr, "invalid \"#pragma maxram 0x%x\" setting\n",
173             pic->maxRAMaddress);
174     return;
175   }
176
177   pic16_finalMapping = Safe_calloc(1+pic->maxRAMaddress,
178                              sizeof(AssignedMemory));
179
180   /* Now initialize the pic16_finalMapping array */
181
182   for(i=0; i<=pic->maxRAMaddress; i++) {
183     pic16_finalMapping[i].reg = NULL;
184     pic16_finalMapping[i].isValid = 0;
185   }
186 }
187
188 /*-----------------------------------------------------------------*
189  *-----------------------------------------------------------------*/
190
191 int pic16_isREGinBank(regs *reg, int bank)
192 {
193
194   if(!reg || !pic)
195     return 0;
196
197   if(pic16_finalMapping[reg->address].bank == bank)
198     return 1;
199
200   return 0;
201 }
202
203 /*-----------------------------------------------------------------*
204  *-----------------------------------------------------------------*/
205 int pic16_REGallBanks(regs *reg)
206 {
207
208   if(!reg || !pic)
209     return 0;
210
211   if (reg->address > pic->maxRAMaddress)
212     return 0;
213
214   return 1;
215
216 }
217
218 /*-----------------------------------------------------------------*
219  *-----------------------------------------------------------------*/
220
221 /*
222  *  pic16_dump_map -- debug stuff
223  */
224
225 void pic16_dump_map(void)
226 {
227   int i;
228
229   for(i=0; i<=pic->maxRAMaddress; i++) {
230     //fprintf(stdout , "addr 0x%02x is %s\n", i, ((pic16_finalMapping[i].isValid) ? "valid":"invalid"));
231
232     if(pic16_finalMapping[i].isValid) {
233       fprintf(stderr,"addr: 0x%02x",i);
234       if(pic16_finalMapping[i].isSFR)
235         fprintf(stderr," isSFR");
236       if(pic16_finalMapping[i].reg) 
237         fprintf( stderr, "  reg %s", pic16_finalMapping[i].reg->name);
238       fprintf(stderr, "\n");
239     }
240   }
241
242 }
243
244 void pic16_dump_cblock(FILE *of)
245 {
246   int start=-1;
247   int addr=0;
248   int bank_base;
249
250   //pic16_dump_map();   /* display the register map */
251
252   if (pic->maxRAMaddress < 0) {
253     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
254     return;
255   }
256
257   do {
258
259     if(pic16_finalMapping[addr].reg && !pic16_finalMapping[addr].reg->isEmitted) {
260
261       if(start<0)
262         start = addr;
263     } else {
264       if(start>=0) {
265
266         /* clear the lower 7-bits of the start address of the first
267          * variable declared in this bank. The upper bits for the mid
268          * range pics are the bank select bits.
269          */
270
271         bank_base = start & 0xfff8;
272
273         /* The bank number printed in the cblock comment tacitly
274          * assumes that the first register in the contiguous group
275          * of registers represents the bank for the whole group */
276
277         if ((pic16_finalMapping[start].bank == 0 && start <= 0x7f) ||
278             pic16_finalMapping[start].isSFR)
279           fprintf(of,"  cblock  0X%04X\t; Access Bank\n",start);
280         else
281           fprintf(of,"  cblock  0X%04X\t; Bank %d\n",start,pic16_finalMapping[start].bank);
282
283         for( ; start < addr; start++) {
284           if((pic16_finalMapping[start].reg) && !pic16_finalMapping[start].reg->isEmitted ) {
285             fprintf(of,"\t%s",pic16_finalMapping[start].reg->name);
286
287             /* If this register is aliased in multiple banks, then
288              * mangle the variable name with the alias address: */
289             if(pic16_finalMapping[start].alias & start)
290               fprintf(of,"_%x",bank_base);
291
292             if(pic16_finalMapping[start].instance)
293               fprintf(of,"_%d",pic16_finalMapping[start].instance);
294
295             
296             fputc('\n',of);
297
298             //pic16_finalMapping[start].reg->isEmitted = 1;
299           }
300         }
301
302         fprintf(of,"  endc\n");
303
304         start = -1;
305       }
306
307     }
308
309     addr++;
310
311   } while(addr <= pic->maxRAMaddress);
312   
313
314 }
315
316 /*-----------------------------------------------------------------*
317  *  void pic16_list_valid_pics(int ncols, int list_alias)
318  *
319  * Print out a formatted list of valid PIC devices
320  *
321  * ncols - number of columns in the list.
322  *
323  * list_alias - if non-zero, print all of the supported aliases
324  *              for a device (e.g. F84, 16F84, etc...)
325  *-----------------------------------------------------------------*/
326 void pic16_list_valid_pics(int ncols, int list_alias)
327 {
328   int col,longest;
329   int i,j,k,l;
330
331   if(list_alias)
332     list_alias = sizeof(Pics[0].name) / sizeof(Pics[0].name[0]);
333
334   /* decrement the column number if it's greater than zero */
335   ncols = (ncols > 1) ? ncols-1 : 4;
336
337   /* Find the device with the longest name */
338   for(i=0,longest=0; i<num_of_supported_PICS; i++) {
339     for(j=0; j<=list_alias; j++) {
340       k = strlen(Pics[i].name[j]);
341       if(k>longest)
342         longest = k;
343     }
344   }
345
346   col = 0;
347
348   for(i=0;  i < num_of_supported_PICS; i++) {
349     j = 0;
350     do {
351
352       fprintf(stderr,"%s", Pics[i].name[j]);
353       if(col<ncols) {
354         l = longest + 2 - strlen(Pics[i].name[j]);
355         for(k=0; k<l; k++)
356           fputc(' ',stderr);
357
358         col++;
359
360       } else {
361         fputc('\n',stderr);
362         col = 0;
363       }
364
365     } while(++j<list_alias);
366
367   }
368   if(col != ncols)
369     fputc('\n',stderr);
370
371 }
372
373 /*-----------------------------------------------------------------*
374  *  
375  *-----------------------------------------------------------------*/
376 PIC_device *pic16_find_device(char *name)
377 {
378
379   int i,j;
380
381   if(!name)
382     return NULL;
383
384   for(i = 0; i<num_of_supported_PICS; i++) {
385
386     for(j=0; j<PROCESSOR_NAMES; j++)
387       if(!STRCASECMP(Pics[i].name[j], name) )
388         return &Pics[i];
389   }
390
391   /* not found */
392   return NULL; 
393 }
394
395 /*-----------------------------------------------------------------*
396  *  
397  *-----------------------------------------------------------------*/
398 void pic16_init_pic(char *pic_type)
399 {
400   pic = pic16_find_device(pic_type);
401
402   if(!pic) {
403     if(pic_type)
404       fprintf(stderr, "'%s' was not found.\n", pic_type);
405     else
406       fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
407
408     fprintf(stderr,"Valid devices are:\n");
409
410     pic16_list_valid_pics(4,0);
411     exit(1);
412   }
413
414   pic->maxRAMaddress = -1;
415 }
416
417 /*-----------------------------------------------------------------*
418  *  
419  *-----------------------------------------------------------------*/
420 int pic16_picIsInitialized(void)
421 {
422   if(pic && pic->maxRAMaddress > 0)
423     return 1;
424
425   return 0;
426
427 }
428
429 /*-----------------------------------------------------------------*
430  *  char *pic16_processor_base_name(void) - Include file is derived from this.
431  *-----------------------------------------------------------------*/
432 char *pic16_processor_base_name(void)
433 {
434
435   if(!pic)
436     return NULL;
437
438   return pic->name[0];
439 }
440
441 static int isSFR(int address)
442 {
443
444   if( (address > pic->maxRAMaddress) || !pic16_finalMapping[address].isSFR)
445     return 0;
446
447   return 1;
448
449 }
450
451 /*-----------------------------------------------------------------*
452  *-----------------------------------------------------------------*/
453 static int validAddress(int address, int reg_size)
454 {
455   int i;
456
457   if (pic->maxRAMaddress < 0) {
458     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
459     return 0;
460   }
461   //  fprintf(stderr, "validAddress: Checking 0x%04x\n",address);
462   if(address > pic->maxRAMaddress)
463     return 0;
464
465   for (i=0; i<reg_size; i++)
466     if(!pic16_finalMapping[address + i].isValid || 
467        pic16_finalMapping[address+i].reg ||
468        pic16_finalMapping[address+i].isSFR )
469       return 0;
470
471   return 1;
472 }
473
474 /*-----------------------------------------------------------------*
475  *-----------------------------------------------------------------*/
476 static void mapRegister(regs *reg)
477 {
478
479   int i;
480   int alias;
481
482   if(!reg || !reg->size) {
483     fprintf(stderr,"WARNING: %s:%s:%d Bad register\n",__FILE__,__FUNCTION__,__LINE__);
484     return;
485   }
486
487   if (pic->maxRAMaddress < 0) {
488     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
489     return;
490   }
491
492   for(i=0; i<reg->size; i++) {
493
494     alias = pic16_finalMapping[reg->address].alias;
495     reg->alias = alias;
496
497     do {
498
499       //fprintf(stdout,"mapping %s to address 0x%02x, reg size = %d\n",reg->name, (reg->address+alias+i),reg->size);
500
501       pic16_finalMapping[reg->address + alias + i].reg = reg;
502       pic16_finalMapping[reg->address + alias + i].instance = i;
503
504       /* Decrement alias */
505       if(alias)
506         alias -= ((alias & (alias - 1)) ^ alias);
507       else
508         alias--;
509
510     } while (alias>=0);
511   }
512
513   //  fprintf(stderr,"%s - %s addr = 0x%03x, size %d\n",__FUNCTION__,reg->name, reg->address,reg->size);
514
515   reg->isMapped = 1;
516
517 }
518
519 /*-----------------------------------------------------------------*
520  *-----------------------------------------------------------------*/
521 static int assignRegister(regs *reg, int start_address)
522 {
523   int i;
524
525   //fprintf(stderr,"%s -  %s start_address = 0x%03x\n",__FUNCTION__,reg->name, start_address);
526   if(reg->isFixed) {
527
528     if (validAddress(reg->address,reg->size)) {
529       //fprintf(stderr,"%s -  %s address = 0x%03x\n",__FUNCTION__,reg->name, reg->address);
530       mapRegister(reg);
531       return reg->address;
532     }
533
534     if( isSFR(reg->address)) {
535       mapRegister(reg);
536       return reg->address;
537     }
538
539     //fprintf(stderr, "WARNING: Ignoring Out of Range register assignment at fixed address %d, %s\n",
540     //    reg->address, reg->name);
541
542   } else {
543
544     /* This register does not have a fixed address requirement
545      * so we'll search through all availble ram address and
546      * assign the first one */
547
548     for (i=start_address; i<=pic->maxRAMaddress; i++) {
549
550       if (validAddress(i,reg->size)) {
551         reg->address = i;
552         mapRegister(reg);
553         return i;
554       }
555     }
556
557     fprintf(stderr, "WARNING: No more RAM available for %s\n",reg->name);
558
559   }
560
561   return -1;
562 }
563
564 /*-----------------------------------------------------------------*
565  *-----------------------------------------------------------------*/
566 void pic16_assignFixedRegisters(set *regset)
567 {
568   regs *reg;
569
570   for (reg = setFirstItem(regset) ; reg ; 
571        reg = setNextItem(regset)) {
572
573     if(reg->isFixed) 
574       assignRegister(reg,0);
575   }
576
577 }
578
579 /*-----------------------------------------------------------------*
580  *-----------------------------------------------------------------*/
581 void pic16_assignRelocatableRegisters(set *regset, int used)
582 {
583
584   regs *reg;
585   int address = 0;
586
587   for (reg = setFirstItem(regset) ; reg ; 
588        reg = setNextItem(regset)) {
589
590     //fprintf(stdout,"assigning %s isFixed=%d, wasUsed=%d\n",reg->name,reg->isFixed,reg->wasUsed);
591
592     if((!reg->isFixed) && ( used || reg->wasUsed))
593       address = assignRegister(reg,address);
594
595   }
596
597 }
598
599
600 /*-----------------------------------------------------------------*
601  *  void pic16_assignConfigWordValue(int address, int value)
602  *
603  * All high performance RISC CPU PICs have seven config word starting
604  * at address 0x300000.
605  * This routine will assign a value to that address.
606  *
607  *-----------------------------------------------------------------*/
608
609 void pic16_assignConfigWordValue(int address, int value)
610 {
611   switch(address) {
612   case CONFIG1H_WORD_ADDRESS:
613     config1h_word = value;
614     break;
615   case CONFIG2L_WORD_ADDRESS:
616     config2l_word = value;
617     break;
618   case CONFIG2H_WORD_ADDRESS:
619     config2h_word = value;
620     break;
621   case CONFIG3H_WORD_ADDRESS:
622     config3h_word = value;
623     break;
624   case CONFIG4L_WORD_ADDRESS:
625     config4l_word = value;
626     break;
627   case CONFIG5L_WORD_ADDRESS:
628     config5l_word = value;
629     break;
630   case CONFIG5H_WORD_ADDRESS:
631     config5h_word = value;
632     break;
633   case CONFIG6L_WORD_ADDRESS:
634     config6l_word = value;
635     break;
636   case CONFIG6H_WORD_ADDRESS:
637     config6h_word = value;
638     break;
639   case CONFIG7L_WORD_ADDRESS:
640     config7l_word = value;
641     break;
642   case CONFIG7H_WORD_ADDRESS:
643     config7h_word = value;
644     break;
645   }
646
647   //fprintf(stderr,"setting config word to 0x%x\n",value);
648
649 }
650 /*-----------------------------------------------------------------*
651  * int pic16_getConfigWord(int address)
652  *
653  * Get the current value of the config word.
654  *
655  *-----------------------------------------------------------------*/
656
657 int pic16_getConfigWord(int address)
658 {
659   switch(address) {
660   case CONFIG1H_WORD_ADDRESS:
661     return config1h_word;
662   case CONFIG2L_WORD_ADDRESS:
663     return config2l_word;
664   case CONFIG2H_WORD_ADDRESS:
665     return config2h_word;
666   case CONFIG3H_WORD_ADDRESS:
667     return config3h_word;
668   case CONFIG4L_WORD_ADDRESS:
669     return config4l_word;
670   case CONFIG5L_WORD_ADDRESS:
671     return config5l_word;
672   case CONFIG5H_WORD_ADDRESS:
673     return config5h_word;
674   case CONFIG6L_WORD_ADDRESS:
675     return config6l_word;
676   case CONFIG6H_WORD_ADDRESS:
677     return config6h_word;
678   case CONFIG7L_WORD_ADDRESS:
679     return config7l_word;
680   case CONFIG7H_WORD_ADDRESS:
681     return config7h_word;
682   default:
683     return 0;
684   }
685 }
686