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