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