Lined up indentation.
[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 }