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