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