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