Register Optimizer was ignoring volatility of SFRs
[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 /* 16F627 */
38 memRange p16f627_mem[] = {
39   {0x20,  0x6f,  0x00,  0},
40   {0xa0,  0xef,  0x00,  1},
41   {0x120, 0x14f, 0x00,  2},
42   {0x70,  0x7f,  0x180, 0},
43   {-1,    -1,    -1,   -1}     /* end indicator */
44 };
45 memRange p16f627_sfr[] = {
46   {0x00,  0x00,  0x180, 0},
47   {0x01,  0x01,  0x100, 0},
48   {0x02,  0x04,  0x180, 0},
49   {0x05,  0x05,  0x000, 0},
50   {0x06,  0x06,  0x100, 0},
51   {0x81,  0x81,  0x100, 1},
52   {0x85,  0x85,  0x000, 1},
53   {0x86,  0x86,  0x100, 1},
54   {0x0a,  0x0b,  0x180, 0},
55   {0x0c,  0x0c,  0x000, 0},
56   {0x0e,  0x12,  0x000, 0},
57   {0x15,  0x1a,  0x000, 0},
58   {0x1f,  0x1f,  0x000, 0},
59   {0x8e,  0x8e,  0x000, 1},
60   {0x92,  0x92,  0x000, 1},
61   {0x98,  0x9d,  0x000, 1},
62   {0x9f,  0x9f,  0x000, 1},
63
64   {-1,    -1,    -1,   -1}     /* end indicator */
65 };
66
67 /* 16F84 */
68 memRange p16f84_mem[] = {
69   {0x0c,  0x4f,  0x80,  0},
70   {-1,    -1,    -1,   -1}     /* end indicator */
71 };
72 memRange p16f84_sfr[] = {
73   {0x01,  0x01,  0x00, 0},
74   {0x02,  0x04,  0x80, 0},
75   {0x05,  0x06,  0x00, 0},
76   {0x81,  0x81,  0x00, 1},
77   {0x85,  0x86,  0x00, 1},
78   {0x08,  0x09,  0x00, 0},
79   {0x88,  0x89,  0x00, 1},
80   {0x0a,  0x0b,  0x80, 0},
81   {-1,    -1,    -1,   -1}     /* end indicator */
82 };
83
84 /* 16F877 */
85 memRange p16f877_mem[] = {
86   {0x20,  0x6f,  0x00,  0},
87   {0xa0,  0xef,  0x00,  1},
88   {0x110, 0x16f, 0x00,  2},
89   {0x190, 0x1ef, 0x00,  3},
90   {0x70,  0x7f,  0x180, 0},
91   {-1,    -1,    -1,   -1}     /* end indicator */
92 };
93 memRange p16f877_sfr[] = {
94   {0x00,  0x00,  0x180, 0},
95   {0x01,  0x01,  0x100, 0},
96   {0x02,  0x04,  0x180, 0},
97   {0x05,  0x05,  0x000, 0},
98   {0x85,  0x85,  0x000, 1},
99   {0x81,  0x81,  0x100, 1},
100   {0x06,  0x06,  0x100, 0},
101   {0x86,  0x86,  0x100, 1},
102   {0x07,  0x09,  0x000, 0},
103   {0x87,  0x89,  0x000, 1},
104   {0x0a,  0x0b,  0x180, 0},
105   {0x0c,  0x1f,  0x000, 0},
106   {0x8c,  0x8e,  0x000, 1},
107   {0x91,  0x94,  0x000, 1},
108   {0x98,  0x99,  0x000, 1},
109   {0x9e,  0x9f,  0x000, 1},
110   {0x10c, 0x10f, 0x000, 2},
111   {0x18c, 0x18f, 0x000, 3},
112
113   {-1,    -1,    -1,   -1}     /* end indicator */
114 };
115
116 /* 16F873 */
117 memRange p16f873_mem[] = {
118   {0x20,  0x7f,  0x100, 0},
119   {0xa0,  0xff,  0x100, 1},
120   {-1,    -1,    -1,   -1}     /* end indicator */
121 };
122 memRange p16f873_sfr[] = {
123   {0x00,  0x00,  0x180, 0},
124   {0x01,  0x01,  0x100, 0},
125   {0x02,  0x04,  0x180, 0},
126   {0x05,  0x05,  0x000, 0},
127   {0x85,  0x85,  0x000, 1},
128   {0x81,  0x81,  0x100, 1},
129   {0x06,  0x06,  0x100, 0},
130   {0x86,  0x86,  0x100, 1},
131   {0x07,  0x09,  0x000, 0},
132   {0x87,  0x89,  0x000, 1},
133   {0x0a,  0x0b,  0x180, 0},
134   {0x0c,  0x1f,  0x000, 0},
135   {0x8c,  0x8e,  0x000, 1},
136   {0x91,  0x94,  0x000, 1},
137   {0x98,  0x99,  0x000, 1},
138   {0x9e,  0x9f,  0x000, 1},
139   {0x10c, 0x10f, 0x000, 2},
140   {0x18c, 0x18f, 0x000, 3},
141
142   {-1,    -1,    -1,   -1}     /* end indicator */
143 };
144
145 static PIC_device Pics[] = {
146   {
147     {"p16f627", "16f627", "pic16f627", "f627"}, /* processor name */
148     p16f627_mem,                     /* ram mem map */
149     p16f627_sfr,                     /* sfr mem map */
150     0,                               /* max ram address (calculated) */
151     0x80,                            /* Bank Mask */
152   },
153
154   {
155     {"p16f628", "16f628", "pic16f628", "f628"},
156     p16f627_mem,
157     p16f627_sfr,
158     0,
159     0x80,
160   },
161
162   {
163     {"p16f84", "16f84", "pic16f84", "f84"},
164     p16f84_mem,
165     p16f84_sfr,
166     0,
167     0x80,
168   },
169
170   {
171     {"p16f873", "16f873", "pic16f873", "f873"},
172     p16f873_mem,
173     p16f873_sfr,
174     0,
175     0x180,
176   },
177
178   {
179     {"p16f877", "16f877", "pic16f877", "f877"},
180     p16f877_mem,
181     p16f877_sfr,
182     0,
183     0x180,
184   },
185
186 };
187
188 static int num_of_supported_PICS = sizeof(Pics)/sizeof(PIC_device);
189
190 #define DEFAULT_PIC "f877"
191
192 static PIC_device *pic=NULL;
193
194 AssignedMemory *finalMapping=NULL;
195
196 #define CONFIG_WORD_ADDRESS 0x2007
197 #define DEFAULT_CONFIG_WORD 0x3fff
198
199 static unsigned int config_word = DEFAULT_CONFIG_WORD;
200
201 /*-----------------------------------------------------------------*
202  *
203  * void addMem(memRange *ranges,int type)
204  *
205  *
206  *-----------------------------------------------------------------*/
207
208 static void addMem(memRange *ranges,int type)
209 {
210   memRange *r = ranges;
211   int i;
212
213   do {
214
215     int alias = r->alias;
216
217     do {
218
219       for(i=r->start_address; i<= r->end_address; i++) {
220         if(i <= pic->maxRAMaddress) {
221           finalMapping[i | alias].isValid = 1;
222           finalMapping[i | alias].alias = r->alias;
223           finalMapping[i | alias].bank  = r->bank;
224           if(type) {
225             /* hack for now */
226             finalMapping[i | alias].isSFR  = 1;
227           } else
228             finalMapping[i | alias].isSFR  = 0;
229         }
230       }
231
232       /* Decrement alias */
233       if(alias)
234         alias -= ((alias & (alias - 1)) ^ alias);
235         else
236           alias--;
237         
238     } while(alias >= 0);
239
240     r++;
241
242   } while (r->start_address >= 0);
243
244
245 }
246
247 /*-----------------------------------------------------------------*
248  *-----------------------------------------------------------------*/
249
250 int isREGinBank(regs *reg, int bank)
251 {
252
253   if(!reg || !pic)
254     return 0;
255
256   if(((reg->address | reg->alias) & pic->bankMask & bank) == bank)
257     return 1;
258
259   return 0;
260 }
261
262 /*-----------------------------------------------------------------*
263  *-----------------------------------------------------------------*/
264 int REGallBanks(regs *reg)
265 {
266
267   if(!reg || !pic)
268     return 0;
269
270   return ((reg->address | reg->alias) & pic->bankMask);
271
272 }
273
274 /*-----------------------------------------------------------------*
275  *-----------------------------------------------------------------*/
276
277 static void addMaps(PIC_device *pPic)
278 {
279   int i;
280   memRange *r;
281
282   if(!pPic)
283     return;
284
285
286   /* First, find the maximum address */
287
288   r = pPic->ram;
289   pPic->maxRAMaddress = 0;
290
291   do {
292
293     if((r->end_address | r->alias) > pPic->maxRAMaddress)
294       pPic->maxRAMaddress = r->end_address | r->alias;
295
296     r++;
297
298   } while (r->start_address >= 0);
299
300
301
302   finalMapping = Safe_calloc(1+pPic->maxRAMaddress, sizeof(AssignedMemory));
303
304   /* Now initialize the finalMapping array */
305
306   for(i=0; i<=pPic->maxRAMaddress; i++) {
307     finalMapping[i].reg = NULL;
308     finalMapping[i].isValid = 0;
309   }
310
311   addMem(pPic->ram,0); /* add general purpose regs to the map */
312   addMem(pPic->sfr,1); /* Add SFR's to the memmap */
313
314 }
315
316 /*
317  *  dump_map -- debug stuff
318  */
319
320 void dump_map(void)
321 {
322   int i;
323
324   for(i=0; i<=pic->maxRAMaddress; i++) {
325     //fprintf(stdout , "addr 0x%02x is %s\n", i, ((finalMapping[i].isValid) ? "valid":"invalid"));
326
327     if(finalMapping[i].isValid) {
328       fprintf(stderr,"addr: 0x%02x",i);
329       if(finalMapping[i].isSFR)
330         fprintf(stderr," isSFR");
331       if(finalMapping[i].reg) 
332         fprintf( stderr, "  reg %s", finalMapping[i].reg->name);
333       fprintf(stderr, "\n");
334     }
335   }
336
337 }
338
339 void dump_cblock(FILE *of)
340 {
341   int start=-1;
342   int addr=0;
343   int bank_base;
344
345   //dump_map();   /* display the register map */
346
347   do {
348
349     if(finalMapping[addr].reg && !finalMapping[addr].reg->isEmitted) {
350
351       if(start<0)
352         start = addr;
353     } else {
354       if(start>=0) {
355
356         /* clear the lower 7-bits of the start address of the first
357          * variable declared in this bank. The upper bits for the mid
358          * range pics are the bank select bits.
359          */
360
361         bank_base = start & 0xfff8;
362
363         /* The bank number printed in the cblock comment tacitly
364          * assumes that the first register in the contiguous group
365          * of registers represents the bank for the whole group */
366
367         fprintf(of,"  cblock  0X%04X\t; Bank %d\n",start,finalMapping[start].bank);
368
369         for( ; start < addr; start++) {
370           if((finalMapping[start].reg) && !finalMapping[start].reg->isEmitted ) {
371             fprintf(of,"\t%s",finalMapping[start].reg->name);
372
373             /* If this register is aliased in multiple banks, then
374              * mangle the variable name with the alias address: */
375             if(finalMapping[start].alias & start)
376               fprintf(of,"_%x",bank_base);
377
378             if(finalMapping[start].instance)
379               fprintf(of,"_%d",finalMapping[start].instance);
380
381             
382             fputc('\n',of);
383
384             //finalMapping[start].reg->isEmitted = 1;
385           }
386         }
387
388         fprintf(of,"  endc\n");
389
390         start = -1;
391       }
392
393     }
394
395     addr++;
396
397   } while(addr <= pic->maxRAMaddress);
398   
399
400 }
401
402 /*-----------------------------------------------------------------*
403  *  void list_valid_pics(int ncols, int list_alias)
404  *
405  * Print out a formatted list of valid PIC devices
406  *
407  * ncols - number of columns in the list.
408  *
409  * list_alias - if non-zero, print all of the supported aliases
410  *              for a device (e.g. F84, 16F84, etc...)
411  *-----------------------------------------------------------------*/
412 void list_valid_pics(int ncols, int list_alias)
413 {
414   int col,longest;
415   int i,j,k,l;
416
417   if(list_alias)
418     list_alias = sizeof(Pics[0].name) / sizeof(Pics[0].name[0]);
419
420   /* decrement the column number if it's greater than zero */
421   ncols = (ncols > 1) ? ncols-1 : 4;
422
423   /* Find the device with the longest name */
424   for(i=0,longest=0; i<num_of_supported_PICS; i++) {
425     for(j=0; j<=list_alias; j++) {
426       k = strlen(Pics[i].name[j]);
427       if(k>longest)
428         longest = k;
429     }
430   }
431
432   col = 0;
433
434   for(i=0;  i < num_of_supported_PICS; i++) {
435     j = 0;
436     do {
437
438       fprintf(stderr,"%s", Pics[i].name[j]);
439       if(col<ncols) {
440         l = longest + 2 - strlen(Pics[i].name[j]);
441         for(k=0; k<l; k++)
442           fputc(' ',stderr);
443
444         col++;
445
446       } else {
447         fputc('\n',stderr);
448         col = 0;
449       }
450
451     } while(++j<list_alias);
452
453   }
454   if(col != ncols)
455     fputc('\n',stderr);
456
457 }
458
459 /*-----------------------------------------------------------------*
460  *  
461  *-----------------------------------------------------------------*/
462 PIC_device *find_device(char *name)
463 {
464
465   int i,j;
466
467   if(!name)
468     return NULL;
469
470   for(i = 0; i<num_of_supported_PICS; i++) {
471
472     for(j=0; j<PROCESSOR_NAMES; j++)
473       if(!STRCASECMP(Pics[i].name[j], name) )
474         return &Pics[i];
475   }
476
477   /* not found */
478   return NULL; 
479 }
480
481 /*-----------------------------------------------------------------*
482  *  
483  *-----------------------------------------------------------------*/
484 void init_pic(char *pic_type)
485 {
486   pic = find_device(pic_type);
487
488   if(!pic) {
489     if(pic_type)
490       fprintf(stderr, "'%s' was not found.\n", pic_type);
491     else
492       fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
493
494     fprintf(stderr,"Valid devices are:\n");
495
496     list_valid_pics(4,0);
497     exit(1);
498   }
499
500   
501   addMaps(pic);
502
503
504 }
505
506 /*-----------------------------------------------------------------*
507  *  char *processor_base_name(void) - Include file is derived from this.
508  *-----------------------------------------------------------------*/
509 char *processor_base_name(void)
510 {
511
512   if(!pic)
513     return NULL;
514
515   return pic->name[0];
516 }
517
518 int isSFR(int address)
519 {
520
521   if( (address > pic->maxRAMaddress) || !finalMapping[address].isSFR)
522     return 0;
523
524   return 1;
525
526 }
527
528 int validAddress(int address, int reg_size)
529 {
530   int i;
531
532   if(address > pic->maxRAMaddress)
533     return 0;
534
535   for (i=0; i<reg_size; i++)
536     if(!finalMapping[address + i].isValid || 
537        finalMapping[address+i].reg ||
538        finalMapping[address+i].isSFR )
539       return 0;
540
541   return 1;
542 }
543
544 void mapRegister(regs *reg)
545 {
546
547   int i;
548   int alias;
549
550   if(!reg || !reg->size) {
551     fprintf(stderr,"WARNING: %s:%s:%d Bad register\n",__FILE__,__FUNCTION__,__LINE__);
552     return;
553   }
554
555   for(i=0; i<reg->size; i++) {
556
557     alias = finalMapping[reg->address].alias;
558     reg->alias = alias;
559
560     do {
561
562       //fprintf(stdout,"mapping %s to address 0x%02x, reg size = %d\n",reg->name, (reg->address+alias+i),reg->size);
563
564       finalMapping[reg->address + alias + i].reg = reg;
565       finalMapping[reg->address + alias + i].instance = i;
566
567       /* Decrement alias */
568       if(alias)
569         alias -= ((alias & (alias - 1)) ^ alias);
570       else
571         alias--;
572
573     } while (alias>=0);
574   }
575
576   //  fprintf(stderr,"%s - %s addr = 0x%03x, size %d\n",__FUNCTION__,reg->name, reg->address,reg->size);
577
578   reg->isMapped = 1;
579
580 }
581
582 int assignRegister(regs *reg, int start_address)
583 {
584   int i;
585
586   //fprintf(stderr,"%s -  %s start_address = 0x%03x\n",__FUNCTION__,reg->name, start_address);
587   if(reg->isFixed) {
588
589     if (validAddress(reg->address,reg->size)) {
590       fprintf(stderr,"%s -  %s address = 0x%03x\n",__FUNCTION__,reg->name, reg->address);
591       mapRegister(reg);
592       return reg->address;
593     }
594
595     if( isSFR(reg->address)) {
596       mapRegister(reg);
597       return reg->address;
598     }
599     fprintf(stderr, "WARNING: Ignoring Out of Range register assignment at fixed address %d, %s\n",
600             reg->address, reg->name);
601
602   } else {
603
604     /* This register does not have a fixed address requirement
605      * so we'll search through all availble ram address and
606      * assign the first one */
607
608     for (i=start_address; i<=pic->maxRAMaddress; i++) {
609
610       if (validAddress(i,reg->size)) {
611         reg->address = i;
612         mapRegister(reg);
613         return i;
614       }
615     }
616
617     fprintf(stderr, "WARNING: No more RAM available\n");
618
619   }
620
621   return -1;
622 }
623
624 void assignFixedRegisters(set *regset)
625 {
626   regs *reg;
627
628   for (reg = setFirstItem(regset) ; reg ; 
629        reg = setNextItem(regset)) {
630
631     if(reg->isFixed) 
632       assignRegister(reg,0);
633   }
634
635 }
636
637 void assignRelocatableRegisters(set *regset, int used)
638 {
639
640   regs *reg;
641   int address = 0;
642
643   for (reg = setFirstItem(regset) ; reg ; 
644        reg = setNextItem(regset)) {
645
646     //fprintf(stdout,"assigning %s isFixed=%d, wasUsed=%d\n",reg->name,reg->isFixed,reg->wasUsed);
647
648     if((!reg->isFixed) && ( used || reg->wasUsed))
649       address = assignRegister(reg,address);
650
651   }
652
653 }
654
655
656 /*-----------------------------------------------------------------*
657  *  void assignConfigWordValue(int address, int value)
658  *
659  * All midrange PICs have one config word at address 0x2007.
660  * This routine will assign a value to that address.
661  *
662  *-----------------------------------------------------------------*/
663
664 void assignConfigWordValue(int address, int value)
665 {
666   if(CONFIG_WORD_ADDRESS == address)
667     config_word = value;
668
669   //fprintf(stderr,"setting config word to 0x%x\n",value);
670
671 }
672 /*-----------------------------------------------------------------*
673  * int getConfigWord(int address)
674  *
675  * Get the current value of the config word.
676  *
677  *-----------------------------------------------------------------*/
678
679 int getConfigWord(int address)
680 {
681   if(CONFIG_WORD_ADDRESS == address)
682     return config_word;
683
684   else
685     return 0;
686
687 }