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