Applied patch from Kevin L. Pauba that added the #pragma memory declaration feature...
[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     0x80,                            /* Bank Mask */
44   },
45
46   {
47     {"p16f628", "16f628", "pic16f628", "f628"},
48     (memRange *)NULL,
49     (memRange *)NULL,
50     0,
51     0x80,
52   },
53
54   {
55     {"p16f84", "16f84", "pic16f84", "f84"},
56     (memRange *)NULL,
57     (memRange *)NULL,
58     0,
59     0x80,
60   },
61
62   {
63     {"p16f873", "16f873", "pic16f873", "f873"},
64     (memRange *)NULL,
65     (memRange *)NULL,
66     0,
67     0x180,
68   },
69
70   {
71     {"p16f877", "16f877", "pic16f877", "f877"},
72     (memRange *)NULL,
73     (memRange *)NULL,
74     0,
75     0x180,
76   },
77
78 };
79
80 static int num_of_supported_PICS = sizeof(Pics)/sizeof(PIC_device);
81
82 #define DEFAULT_PIC "f877"
83
84 static PIC_device *pic=NULL;
85
86 AssignedMemory *finalMapping=NULL;
87
88 #define CONFIG_WORD_ADDRESS 0x2007
89 #define DEFAULT_CONFIG_WORD 0x3fff
90
91 static unsigned int config_word = DEFAULT_CONFIG_WORD;
92
93 void addMemRange(memRange *r, int type)
94 {
95   int i;
96   int alias = r->alias;
97
98   if (pic->maxRAMaddress < 0) {
99     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
100     return;
101   }
102
103   do {
104     for (i=r->start_address; i<= r->end_address; i++) {
105       if (i <= pic->maxRAMaddress) {
106         finalMapping[i | alias].isValid = 1;
107         finalMapping[i | alias].alias = r->alias;
108         finalMapping[i | alias].bank  = r->bank;
109         if(type) {
110           /* hack for now */
111           finalMapping[i | alias].isSFR  = 1;
112         } else {
113           finalMapping[i | alias].isSFR  = 0;
114         }
115       }
116     }
117
118     /* Decrement alias */
119     if (alias) {
120       alias -= ((alias & (alias - 1)) ^ alias);
121     } else {
122       alias--;
123     }
124
125   } while (alias >= 0);
126 }
127
128 void setMaxRAM(int size)
129 {
130   int i;
131   pic->maxRAMaddress = size;
132
133   if (pic->maxRAMaddress < 0) {
134     fprintf(stderr, "invalid \"#pragma maxram 0x%x\" setting\n",
135             pic->maxRAMaddress);
136     return;
137   }
138
139   finalMapping = Safe_calloc(1+pic->maxRAMaddress,
140                              sizeof(AssignedMemory));
141
142   /* Now initialize the finalMapping array */
143
144   for(i=0; i<=pic->maxRAMaddress; i++) {
145     finalMapping[i].reg = NULL;
146     finalMapping[i].isValid = 0;
147   }
148 }
149
150 /*-----------------------------------------------------------------*
151  *-----------------------------------------------------------------*/
152
153 int isREGinBank(regs *reg, int bank)
154 {
155
156   if(!reg || !pic)
157     return 0;
158
159   if(((reg->address | reg->alias) & pic->bankMask & bank) == bank)
160     return 1;
161
162   return 0;
163 }
164
165 /*-----------------------------------------------------------------*
166  *-----------------------------------------------------------------*/
167 int REGallBanks(regs *reg)
168 {
169
170   if(!reg || !pic)
171     return 0;
172
173   return ((reg->address | reg->alias) & pic->bankMask);
174
175 }
176
177 /*-----------------------------------------------------------------*
178  *-----------------------------------------------------------------*/
179
180 /*
181  *  dump_map -- debug stuff
182  */
183
184 void dump_map(void)
185 {
186   int i;
187
188   for(i=0; i<=pic->maxRAMaddress; i++) {
189     //fprintf(stdout , "addr 0x%02x is %s\n", i, ((finalMapping[i].isValid) ? "valid":"invalid"));
190
191     if(finalMapping[i].isValid) {
192       fprintf(stderr,"addr: 0x%02x",i);
193       if(finalMapping[i].isSFR)
194         fprintf(stderr," isSFR");
195       if(finalMapping[i].reg) 
196         fprintf( stderr, "  reg %s", finalMapping[i].reg->name);
197       fprintf(stderr, "\n");
198     }
199   }
200
201 }
202
203 void dump_cblock(FILE *of)
204 {
205   int start=-1;
206   int addr=0;
207   int bank_base;
208
209   //dump_map();   /* display the register map */
210
211   if (pic->maxRAMaddress < 0) {
212     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
213     return;
214   }
215
216   do {
217
218     if(finalMapping[addr].reg && !finalMapping[addr].reg->isEmitted) {
219
220       if(start<0)
221         start = addr;
222     } else {
223       if(start>=0) {
224
225         /* clear the lower 7-bits of the start address of the first
226          * variable declared in this bank. The upper bits for the mid
227          * range pics are the bank select bits.
228          */
229
230         bank_base = start & 0xfff8;
231
232         /* The bank number printed in the cblock comment tacitly
233          * assumes that the first register in the contiguous group
234          * of registers represents the bank for the whole group */
235
236         fprintf(of,"  cblock  0X%04X\t; Bank %d\n",start,finalMapping[start].bank);
237
238         for( ; start < addr; start++) {
239           if((finalMapping[start].reg) && !finalMapping[start].reg->isEmitted ) {
240             fprintf(of,"\t%s",finalMapping[start].reg->name);
241
242             /* If this register is aliased in multiple banks, then
243              * mangle the variable name with the alias address: */
244             if(finalMapping[start].alias & start)
245               fprintf(of,"_%x",bank_base);
246
247             if(finalMapping[start].instance)
248               fprintf(of,"_%d",finalMapping[start].instance);
249
250             
251             fputc('\n',of);
252
253             //finalMapping[start].reg->isEmitted = 1;
254           }
255         }
256
257         fprintf(of,"  endc\n");
258
259         start = -1;
260       }
261
262     }
263
264     addr++;
265
266   } while(addr <= pic->maxRAMaddress);
267   
268
269 }
270
271 /*-----------------------------------------------------------------*
272  *  void list_valid_pics(int ncols, int list_alias)
273  *
274  * Print out a formatted list of valid PIC devices
275  *
276  * ncols - number of columns in the list.
277  *
278  * list_alias - if non-zero, print all of the supported aliases
279  *              for a device (e.g. F84, 16F84, etc...)
280  *-----------------------------------------------------------------*/
281 void list_valid_pics(int ncols, int list_alias)
282 {
283   int col,longest;
284   int i,j,k,l;
285
286   if(list_alias)
287     list_alias = sizeof(Pics[0].name) / sizeof(Pics[0].name[0]);
288
289   /* decrement the column number if it's greater than zero */
290   ncols = (ncols > 1) ? ncols-1 : 4;
291
292   /* Find the device with the longest name */
293   for(i=0,longest=0; i<num_of_supported_PICS; i++) {
294     for(j=0; j<=list_alias; j++) {
295       k = strlen(Pics[i].name[j]);
296       if(k>longest)
297         longest = k;
298     }
299   }
300
301   col = 0;
302
303   for(i=0;  i < num_of_supported_PICS; i++) {
304     j = 0;
305     do {
306
307       fprintf(stderr,"%s", Pics[i].name[j]);
308       if(col<ncols) {
309         l = longest + 2 - strlen(Pics[i].name[j]);
310         for(k=0; k<l; k++)
311           fputc(' ',stderr);
312
313         col++;
314
315       } else {
316         fputc('\n',stderr);
317         col = 0;
318       }
319
320     } while(++j<list_alias);
321
322   }
323   if(col != ncols)
324     fputc('\n',stderr);
325
326 }
327
328 /*-----------------------------------------------------------------*
329  *  
330  *-----------------------------------------------------------------*/
331 PIC_device *find_device(char *name)
332 {
333
334   int i,j;
335
336   if(!name)
337     return NULL;
338
339   for(i = 0; i<num_of_supported_PICS; i++) {
340
341     for(j=0; j<PROCESSOR_NAMES; j++)
342       if(!STRCASECMP(Pics[i].name[j], name) )
343         return &Pics[i];
344   }
345
346   /* not found */
347   return NULL; 
348 }
349
350 /*-----------------------------------------------------------------*
351  *  
352  *-----------------------------------------------------------------*/
353 void init_pic(char *pic_type)
354 {
355   pic = find_device(pic_type);
356
357   if(!pic) {
358     if(pic_type)
359       fprintf(stderr, "'%s' was not found.\n", pic_type);
360     else
361       fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
362
363     fprintf(stderr,"Valid devices are:\n");
364
365     list_valid_pics(4,0);
366     exit(1);
367   }
368
369   pic->maxRAMaddress = -1;
370 }
371
372 /*-----------------------------------------------------------------*
373  *  char *processor_base_name(void) - Include file is derived from this.
374  *-----------------------------------------------------------------*/
375 char *processor_base_name(void)
376 {
377
378   if(!pic)
379     return NULL;
380
381   return pic->name[0];
382 }
383
384 int isSFR(int address)
385 {
386
387   if( (address > pic->maxRAMaddress) || !finalMapping[address].isSFR)
388     return 0;
389
390   return 1;
391
392 }
393
394 int validAddress(int address, int reg_size)
395 {
396   int i;
397
398   if (pic->maxRAMaddress < 0) {
399     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
400     return 0;
401   }
402
403   if(address > pic->maxRAMaddress)
404     return 0;
405
406   for (i=0; i<reg_size; i++)
407     if(!finalMapping[address + i].isValid || 
408        finalMapping[address+i].reg ||
409        finalMapping[address+i].isSFR )
410       return 0;
411
412   return 1;
413 }
414
415 void mapRegister(regs *reg)
416 {
417
418   int i;
419   int alias;
420
421   if(!reg || !reg->size) {
422     fprintf(stderr,"WARNING: %s:%s:%d Bad register\n",__FILE__,__FUNCTION__,__LINE__);
423     return;
424   }
425
426   if (pic->maxRAMaddress < 0) {
427     fprintf(stderr, "missing \"#pragma maxram\" setting\n");
428     return;
429   }
430
431   for(i=0; i<reg->size; i++) {
432
433     alias = finalMapping[reg->address].alias;
434     reg->alias = alias;
435
436     do {
437
438       //fprintf(stdout,"mapping %s to address 0x%02x, reg size = %d\n",reg->name, (reg->address+alias+i),reg->size);
439
440       finalMapping[reg->address + alias + i].reg = reg;
441       finalMapping[reg->address + alias + i].instance = i;
442
443       /* Decrement alias */
444       if(alias)
445         alias -= ((alias & (alias - 1)) ^ alias);
446       else
447         alias--;
448
449     } while (alias>=0);
450   }
451
452   //  fprintf(stderr,"%s - %s addr = 0x%03x, size %d\n",__FUNCTION__,reg->name, reg->address,reg->size);
453
454   reg->isMapped = 1;
455
456 }
457
458 int assignRegister(regs *reg, int start_address)
459 {
460   int i;
461
462   //fprintf(stderr,"%s -  %s start_address = 0x%03x\n",__FUNCTION__,reg->name, start_address);
463   if(reg->isFixed) {
464
465     if (validAddress(reg->address,reg->size)) {
466       fprintf(stderr,"%s -  %s address = 0x%03x\n",__FUNCTION__,reg->name, reg->address);
467       mapRegister(reg);
468       return reg->address;
469     }
470
471     if( isSFR(reg->address)) {
472       mapRegister(reg);
473       return reg->address;
474     }
475     fprintf(stderr, "WARNING: Ignoring Out of Range register assignment at fixed address %d, %s\n",
476             reg->address, reg->name);
477
478   } else {
479
480     /* This register does not have a fixed address requirement
481      * so we'll search through all availble ram address and
482      * assign the first one */
483
484     for (i=start_address; i<=pic->maxRAMaddress; i++) {
485
486       if (validAddress(i,reg->size)) {
487         reg->address = i;
488         mapRegister(reg);
489         return i;
490       }
491     }
492
493     fprintf(stderr, "WARNING: No more RAM available\n");
494
495   }
496
497   return -1;
498 }
499
500 void assignFixedRegisters(set *regset)
501 {
502   regs *reg;
503
504   for (reg = setFirstItem(regset) ; reg ; 
505        reg = setNextItem(regset)) {
506
507     if(reg->isFixed) 
508       assignRegister(reg,0);
509   }
510
511 }
512
513 void assignRelocatableRegisters(set *regset, int used)
514 {
515
516   regs *reg;
517   int address = 0;
518
519   for (reg = setFirstItem(regset) ; reg ; 
520        reg = setNextItem(regset)) {
521
522     //fprintf(stdout,"assigning %s isFixed=%d, wasUsed=%d\n",reg->name,reg->isFixed,reg->wasUsed);
523
524     if((!reg->isFixed) && ( used || reg->wasUsed))
525       address = assignRegister(reg,address);
526
527   }
528
529 }
530
531
532 /*-----------------------------------------------------------------*
533  *  void assignConfigWordValue(int address, int value)
534  *
535  * All midrange PICs have one config word at address 0x2007.
536  * This routine will assign a value to that address.
537  *
538  *-----------------------------------------------------------------*/
539
540 void assignConfigWordValue(int address, int value)
541 {
542   if(CONFIG_WORD_ADDRESS == address)
543     config_word = value;
544
545   //fprintf(stderr,"setting config word to 0x%x\n",value);
546
547 }
548 /*-----------------------------------------------------------------*
549  * int getConfigWord(int address)
550  *
551  * Get the current value of the config word.
552  *
553  *-----------------------------------------------------------------*/
554
555 int getConfigWord(int address)
556 {
557   if(CONFIG_WORD_ADDRESS == address)
558     return config_word;
559
560   else
561     return 0;
562
563 }