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