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