Added support for multiplication. Fixed peep hole bugs (and more functionality to...
[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
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->maxRAMaddress) {
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->maxRAMaddress = 0;
214
215   do {
216
217     if((r->end_address | r->alias) > pPic->maxRAMaddress)
218       pPic->maxRAMaddress = r->end_address | r->alias;
219
220     r++;
221
222   } while (r->start_address >= 0);
223
224
225
226   finalMapping = Safe_calloc(1+pPic->maxRAMaddress, sizeof(AssignedMemory));
227
228   /* Now initialize the finalMapping array */
229
230   for(i=0; i<=pPic->maxRAMaddress; 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->maxRAMaddress; 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->maxRAMaddress);
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   /* decrement the column number if it's greater than zero */
336   ncols = (ncols > 1) ? ncols-1 : 4;
337
338   /* Find the device with the longest name */
339   for(i=0,longest=0; i<num_of_supported_PICS; i++) {
340     for(j=0; j<=list_alias; j++) {
341       k = strlen(Pics[i].name[j]);
342       if(k>longest)
343         longest = k;
344     }
345   }
346
347   col = 0;
348
349   for(i=0;  i < num_of_supported_PICS; i++) {
350     j = 0;
351     do {
352
353       fprintf(stderr,"%s", Pics[i].name[j]);
354       if(col<ncols) {
355         l = longest + 2 - strlen(Pics[i].name[j]);
356         for(k=0; k<l; k++)
357           fputc(' ',stderr);
358
359         col++;
360
361       } else {
362         fputc('\n',stderr);
363         col = 0;
364       }
365
366     } while(++j<list_alias);
367
368   }
369   if(col != ncols)
370     fputc('\n',stderr);
371
372 }
373
374 /*-----------------------------------------------------------------*
375  *  
376  *-----------------------------------------------------------------*/
377 PIC_device *find_device(char *name)
378 {
379
380   int i,j;
381
382   if(!name)
383     return NULL;
384
385   for(i = 0; i<num_of_supported_PICS; i++) {
386
387     for(j=0; j<PROCESSOR_NAMES; j++)
388       if(!STRCASECMP(Pics[i].name[j], name) )
389         return &Pics[i];
390   }
391
392   /* not found */
393   return NULL; 
394 }
395
396 /*-----------------------------------------------------------------*
397  *  
398  *-----------------------------------------------------------------*/
399 void init_pic(char *pic_type)
400 {
401   pic = find_device(pic_type);
402
403   if(!pic) {
404     if(pic_type)
405       fprintf(stderr, "'%s' was not found.\n", pic_type);
406     else
407       fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
408
409     fprintf(stderr,"Valid devices are:\n");
410
411     list_valid_pics(4,0);
412     exit(1);
413   }
414
415   
416   addMaps(pic);
417
418
419 }
420
421 /*-----------------------------------------------------------------*
422  *  char *processor_base_name(void) - Include file is derived from this.
423  *-----------------------------------------------------------------*/
424 char *processor_base_name(void)
425 {
426
427   if(!pic)
428     return NULL;
429
430   return pic->name[0];
431 }
432
433 int isSFR(int address)
434 {
435
436   if( (address > pic->maxRAMaddress) || !finalMapping[address].isSFR)
437     return 0;
438
439   return 1;
440
441 }
442
443 int validAddress(int address, int reg_size)
444 {
445   int i;
446
447   if(address > pic->maxRAMaddress)
448     return 0;
449
450   for (i=0; i<reg_size; i++)
451     if(!finalMapping[address + i].isValid || 
452        finalMapping[address+i].reg ||
453        finalMapping[address+i].isSFR )
454       return 0;
455
456   return 1;
457 }
458
459 void mapRegister(regs *reg)
460 {
461
462   int i;
463   int alias;
464
465   if(!reg || !reg->size) {
466     fprintf(stderr,"WARNING: %s:%s:%d Bad register\n",__FILE__,__FUNCTION__,__LINE__);
467     return;
468   }
469
470   for(i=0; i<reg->size; i++) {
471
472     alias = finalMapping[reg->address].alias;
473     reg->alias = alias;
474
475     do {
476
477       // fprintf(stdout,"mapping %s to address 0x%02x, reg size = %d\n",reg->name, (reg->address+alias+i),reg->size);
478
479       finalMapping[reg->address + alias + i].reg = reg;
480       finalMapping[reg->address + alias + i].instance = i;
481
482       /* Decrement alias */
483       if(alias)
484         alias -= ((alias & (alias - 1)) ^ alias);
485       else
486         alias--;
487
488     } while (alias>=0);
489   }
490
491   //  fprintf(stderr,"%s - %s addr = 0x%03x, size %d\n",__FUNCTION__,reg->name, reg->address,reg->size);
492
493   reg->isMapped = 1;
494
495 }
496
497 int assignRegister(regs *reg, int start_address)
498 {
499   int i;
500
501   //fprintf(stderr,"%s -  %s start_address = 0x%03x\n",__FUNCTION__,reg->name, start_address);
502   if(reg->isFixed) {
503
504     if (validAddress(reg->address,reg->size)) {
505
506       mapRegister(reg);
507       return reg->address;
508     }
509
510     if( isSFR(reg->address)) {
511       mapRegister(reg);
512       return reg->address;
513     }
514     fprintf(stderr, "WARNING: Ignoring Out of Range register assignment at fixed address %d, %s\n",
515             reg->address, reg->name);
516
517   } else {
518
519     /* This register does not have a fixed address requirement
520      * so we'll search through all availble ram address and
521      * assign the first one */
522
523     for (i=start_address; i<=pic->maxRAMaddress; i++) {
524
525       if (validAddress(i,reg->size)) {
526         reg->address = i;
527         mapRegister(reg);
528         return i;
529       }
530     }
531
532     fprintf(stderr, "WARNING: No more RAM available\n");
533
534   }
535
536   return -1;
537 }
538
539 void assignFixedRegisters(set *regset)
540 {
541   regs *reg;
542
543   for (reg = setFirstItem(regset) ; reg ; 
544        reg = setNextItem(regset)) {
545
546     if(reg->isFixed) 
547       assignRegister(reg,0);
548   }
549
550 }
551
552 void assignRelocatableRegisters(set *regset, int used)
553 {
554
555   regs *reg;
556   int address = 0;
557
558   for (reg = setFirstItem(regset) ; reg ; 
559        reg = setNextItem(regset)) {
560
561     // fprintf(stdout,"assigning %s\n",reg->name);
562
563     if((!reg->isFixed) && ( (used==0) || reg->wasUsed))
564       address = assignRegister(reg,address);
565
566   }
567
568 }
569